MySQL索引的一些概念
- 查询执行计划:
执行查询语句之前,MySQL查询优化器会基于cost成本对一条查询语句进行优化,并生成一个执行计划。如果创建的索引太多,优化器会计算每个索引的搜索成本,导致在分析过程中耗时太多,最终影响查询语句的执行效率。
- 查询中,对索引扫描是在存储引擎中进行的,而对数据记录的比较是在Server层中进行的(Using where),所以先回表再过滤记录,是需要将记录行数据从存储引擎搬运到Server层的。
- 回表:我们可以通过二级索引找到B+树中的叶子节点,但是二级索引的叶子节点的字段并不全,只有索引列的值和主键值。我们需要拿着主键值再去聚簇索引(主键索引)的叶子节点中去拿到完整的用户记录,这个过程叫做回表。
- 回表的代价:我们根据name字段查找二级索引的叶子节点的代价还是比较小的,原因有二:
1.叶子节点所在的页通过双向链表进行关联,遍历的速度比较快;
2.MySQL会尽量让同一个索引的叶子节点的数据页在磁盘空间中相邻,尽力避免随机IO。
但是二级索引叶子节点中的主键id的排布就没有任何规律了,毕竟name索引是对name字段进行排序的。进行回表的时候,极有可能出现主键id所在的记录在聚簇索引叶子节点中反复横跳的情况(正如上图中回表的3条线表示的那样),也就是随机IO。如果目标数据页恰好在内存中的话效果倒也不会太差,但如果不在内存中,还要从磁盘中加载一个数据页的内容(16KB)到内存中,这个速度可就太慢了。
是不是说完了回表的代价之后,我会给出一种更高效的搜索方式?不是,回表已经是一种比较高效的搜索方式了,我们需要做的就是尽量地减少回表操作带来的损耗,总结起来就是两点:
1.能不回表就不回;
2.必须回表就减少回表的次数。
接下来先给大家介绍两个与回表相关的重要概念,这两个概念涉及到的方法也是索引使用原则的一部分,因为比较重要,在这里我把这两个概念先解释给大家听。
1.索引覆盖:select 语句后的目标字段,能直接从命中的索引中取得,不需要回表到聚餐索引拿。
2.索引下推:索引条件下推(Index Condition Pushdown,ICP)是MySQL5.6之后完善的功能,默认开启的,就是过滤的动作由下层的存储引擎层通过使用索引来完成,而不需要上推到Server层进行处理。
注:即使满足索引下推的使用条件,查询优化器也未必会使用索引下推,因为可能存在更高效的方式。
由于之前我给name
字段创建了索引,导致一直没有使用索引下推,EXPLAIN
语句显示使用了name
索引,而不是name
和phone
的联合索引;删除name
索引之后,才获得上述截图的效果,大家做实验的时候需要注意。
- 我们要以正确的方式积极拥抱索引:
1.高效发挥已经创建的索引的作用(避免索引失效)
2.为合适的列创建合适的索引(索引创建原则)