1. 覆盖索引
表 user,id(主键),name(普通索引)

当我们想查询 name = 张三 的id 时我们可以使用
select * from user where name = '张三'


这条语句的执行过程为:先去索引树name中找到张三拿到张三的id,再去主键索引树中根据id拿到这条记录,而我们只是需要它的id的,使用这条语句会进行一次回表操作,所以我们可以改为下面语句:

select id from user where name = '张三'

这种方式就叫做覆盖索引,我们可以通过一些联合索引的方式去避免进行二次回表操作。

在开发中使用userMapper.selectByExample方法时, 就会造成二次回表操作,有一丢丢的性能损耗

2. 索引最左前缀
表 user,id(主键),gender(性别),name(姓名),age(年龄)
联合索引(name,age)

当我们查询姓张并且年龄为10岁的男孩时:

select * from user where name like '张%' and age = 10 and gender = 1

它会先找到第一个姓张的记录,然后再向后依次遍历,这种就避免了全表扫描。

一般来说如果建立了 (a,b)联合索引,就不需要在a上单独建立一个索引了,但是如果是根据b来查,那么还是需要在b上建立索引。

3. count(*)的实现

MyISAM:一个表的总行数存在了磁盘上

InnoDB:把数据一行一行地从引擎里面读出来,然后累加

mysql查询出现两次以上的记录条数 mysql二次查询_数据库

mysql查询出现两次以上的记录条数 mysql二次查询_主键_02

count(字段)<count(主建id)<count(1)约等于count(*),因为你查字段的时候,会存在数据io的,而count(*) mysql自己做了优化,不存在任何的文件io

4. 数据库行锁

在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议

假设你负责实现一个电影票在线交易业务,顾客A要在影院B购买电影票。我们简化一点,这个业务需要涉及到以下操作:

  1. 从顾客A账户余额中扣除电影票价;
  2. 给影院B的账户余额增加这张电影票价;
  3. 记录一条交易日志。

1.如果存在3个数据库都需要更新数据,产生行锁 ,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

2.在有多个请求修改数据库时,有可能会产生死锁,数据库去检测死锁会消耗大量的性能,

以影院账户为例,可以考虑放在多条记录上,比如10个记录,影院的账户总额等于这10个记录的值的总和。这样每次要给影院账户加金额的时候,随机选其中一条记录来加。这样每次冲突概率变成原来的1/10,可以减少锁等待个数,也就减少了死锁检测的CPU消耗。增加业务的复杂度,尽量避免死锁的产生.