SQL语句在MySQL中的执行过程
执行SQL语句时,会先查询缓存,如果命中缓存就直接返回结果集,效率挺高,缓存在MySQL8.0开始就移除了,具体为什么下面分析。没有命中缓存就需要进入分析器,作用是解读这条SQL是要干什么,是不是满足语法,都满足了就接着进入优化器,作用是分析如何执行效率比较高,比如使用索引等,结束优化后这条SQL怎么执行基本就确定下来了,最后到执行器,通过接口去存储引擎查询数据并返回。
MySQL中的缓存为何要移除?
缓存通过能提高效率,但是不是绝对的。MySQL的缓存是以key-value形式存在的,key是SQL本身,value是结果集,缓存命中的过程,要求我们写的SQL要跟缓存中的一摸一样,包括字符串大小都得一样,如果不一样就命中不了;所以这就会造成缓存中的结果集有许多都是一样的,这样就浪费了空间;我们对缓存中的数据进行修改等操作,会导致缓存中的相关数据缓存失效被清除,这样有什么影响呢?如果对于数据频繁修改的,就会造成缓存中的数据经常失效被清除,而去缓存命中率低,也很消耗性能,影响效率,所以最终MySQL移除了缓存这一功能。
简单来说就是,对频繁修改的数据不推荐使用缓存。
MySQL的执行计划
在SQL的最前面加上explain
可以打开SQL的执行计划。
其中有几个重要的字段:
- type:访问表的方式,有system、const、eq_ref、ref、index_merge、range、index、all。system和const表示主键或唯一键作为查询条件命中数据一条记录的情况;eq_ref表示主键或者唯一键当作表的连接条件;ref表示使用普通索引作为查询条件,并可能返回多条记录;index_merge表示使用了多个索引;range表示索引的范围查询;index表示访问了整颗索引树;all表示全表扫描。效率从左到右降低。
- key:表示使用到的索引
- key_len:索引的总长度
- extra:额外的信息。如果是using file sort、using temporary的话,分别表示用到了外部的排序没有用到内部索引的排序和使用了临时表的情况,效率都比较低,要优化;如果是using index、using index condition表示分别用到了索引不用回表和使用了索引下推不用回表的情况,效率高。
MySQL的自增主键一定是连续的吗?
不一定。第一种情况,我们设置的初始值和步长不为1,也就是比如刚开始是2,执行后下一次自增值就是4了,因为步长为2;第二种情况,当我们执行insert语句时,此时自增键是2,如果插入失败,比如唯一键冲突了,这种情况下我们下次执行的时候的自增主键就是3了,自增键并不会回退;第三种情况,当我们事务回滚后,自增键也同样不会回滚;第四种情况,批量插入数据,因为批量插入数据,数据库本身并知道要申请多少自增键,所以通常就是第一次申请1,第二次申请2,第三次申请4个,第四次申请8个,所以这时候如果批量插入5条数据,那么下一次的自增值就是8,这种情况也会造成自增主键不连续。
那么,为什么不设置自增主键也可以回退呢?
我们先假设一下可以回退,那么比如现在有两个事务,分别插入一条数据,事务A申请到的自增值是2,事务B申请到的自增值是3,如果事务A回滚了,此时自增值也回退,事务B执行通过提交了,那么下一次的自增值就是3,下一条申请主键得到的就是3,此时插入就会报主键冲突的问题。所以自增键才不进行回退。