explain字段释疑
- id:标识本次执行select的语句顺序,在子查询中有意义。
- select_type:
- SIMPLLE:简单查询,该查询不包含 UNION 或子查询
- PRIMARY:如果查询包含UNION 或子查询,则最外层的查询被标识为PRIMARY
- UNION:表示此查询是 UNION 中的第二个或者随后的查询
- SUBQUERY:子查询中的第一个select语句(该子查询不在from子句中)
- DERIVED:包含在from子句中子查询(也称为派生表)
- table:查询的表
- type:查询方式,性能从好到差:
- system/const:主键/唯一索引查询
- eq_ref:使用唯一索引扫描,或确定返回单条记录。
- ref:使用非唯一索引扫描或唯一索引前缀扫描。
- range:索引范围扫描,存在in、between、>、<等对索引的范围查询场景下。
- index:索引全扫描,按某个非聚集索引扫其所有叶子节点,需要回表,所有有时候不如all。
- all:全表扫描,也就是扫聚集索引的所有叶子节点。
- possible_key:可能使用的索引
- key:实际使用的索引
- key_len:索引长度
- ref:标识where条件中筛选的值,一般是const、func、null、字段名
- rows:扫描行数
Extra:额外信息描述
USE INDEX:推荐一个索引列表给mysql,但也不一定就会用。
- FORCE INDEX:强制使用某个索引,如果给定的索引是合理的,那么确实可以减少mysql在其他索引的上评估成本,如果给定的不对,可能并不如mysql选择出来的索引。
-
索引下推
在5.6版本之后的优化,还有MRR(multi-range read)。
- 先简单说一下MRR,通过将查出来的非聚集索引按主键索引进行重排序,再去回表查询,降低离散读和情况并减少缓存页换出的操作,可以提高效率。
- 我们都mysql结构可以简单划分为应用层+存储引擎层,我们用的sql语句里的where后面的字段并不会每一个字段都会命中索引,比如有idx(username, age),sql语句是where username like ‘larry%’ and age=10
- 5.6版本之前的sql执行逻辑是,先从存储引擎层根据索引由先过滤出符合条件的主键ID列表(也就是会根据idx的username进行过滤,age由于username的模糊查询不会被过滤),然后在应用层进行回表查出剩余where字段的值(也就是age),然后进行过滤(age=10)。
- 而索引下推(Index Condition Pushdown)的逻辑则是第一步一样,第二步则会在存储引擎继续根据索引进行过滤,也就是进行age=10的过滤,极大减少了回表数量。
所以要触发ICP,其实有两点要求:
mysql优化器在选择索引的时候,一个很最重要的参考标准就是扫描行数,当然是越少越好,所以mysql有两种方式来获取扫描行数。
- 索引下潜(Index Dive):调用存储引擎的接口,获取准确的估算数据,成本高。
- 索引统计(Index Statistics):存储引擎会以一定的机制更新每个索引的cardinality值,但这个值并不是实时的,所以存在一定的误差,但该值是可以直接获取到的,成本低。