【Mysql】执行计划的分析---Type本质
type不是看 select 后面的字段也不是单纯看 where 后面的字段。更准确地说type看的是MySQL 访问这张表时采用了什么“找数据的方式”。也就是MySQL 是怎么从表里把数据找出来的。先抓住一句话select后面的字段主要影响是否回表、是否覆盖索引where/join/orderby后面的字段主要影响能不能用索引、用什么方式访问表type是 MySQL 最终选择的访问方式所以你看到有人说看select后面的字段有人说看where后面的字段是因为它们都会影响执行计划但影响点不一样。一、type 主要和 where / join 条件有关比如有表user(id,name,age,city)其中id 是主键 age 有普通索引 name 没有索引1. 根据主键查type constexplainselect*fromuserwhereid1;因为id是主键id 1最多只能查到一条数据。所以type const key PRIMARY这里type是由whereid1决定的。也就是MySQL 通过主键索引一次定位。2. 根据普通索引查type refexplainselect*fromuserwhereage18;age是普通索引age 18可能查出很多人。所以type ref key idx_age这里type也是由whereage18决定的。3. 根据范围查type rangeexplainselect*fromuserwhereage18;因为是范围查询所以type range key idx_age4. 没有索引type ALLexplainselect*fromuserwherename张三;如果name没有索引MySQL 只能全表扫描type ALL key NULL所以大多数情况下type主要看的是where后面的条件有没有索引where后面的条件是等值还是范围where后面的条件用的是主键、唯一索引还是普通索引二、那 select 后面的字段影响什么select后面的字段一般不直接决定 type 的核心类型但它会影响是否需要回表 是否能用覆盖索引 是否只扫描索引就够了看这个例子。假设有联合索引indexidx_age_name(age,name)情况 1select 的字段都在索引里explainselectage,namefromuserwhereage18;因为age和name都在索引idx_age_name里面所以 MySQL 只看索引就能得到结果。可能是type ref key idx_age_name Extra Using index这里type ref是因为where age 18使用普通索引等值查询。而Extra Using index是因为select age, name这两个字段都在索引里不用回表。情况 2select 了索引里没有的字段explainselectage,name,cityfromuserwhereage18;如果city不在索引里MySQL 先通过idx_age_name找到符合age 18的记录然后还要回到主键索引里拿city。可能是type ref key idx_age_name Extra Using where你会发现type 仍然可能是 ref但是Extra变了不能做到覆盖索引了。所以select后面的字段主要影响Extra里的Using index以及是否回表。三、为什么有时候 select 后面的字段会影响 type因为有一种特殊情况如果查询的字段刚好都在某个索引里MySQL 可能会选择扫描索引而不是扫描整张表。比如explainselectagefromuser;如果age有索引那么 MySQL 可能会扫描age这个索引type index key idx_age Extra Using index注意这个 SQL 没有whereselectagefromuser;那为什么还能用索引因为你只查询age而age本身就在索引里MySQL 直接扫描索引就够了。这时type index。它的意思是扫描整棵索引树而不是扫描整张表。再看explainselect*fromuser;如果查所有字段索引里不包含所有字段MySQL 通常只能扫描整张表type ALL key NULL所以你会看到selectagefromuser;可能是type index而select*fromuser;可能是type ALL这就是为什么有人说select后面的字段也会影响type。但本质不是因为select字段在“筛选数据”而是因为select 的字段决定了 MySQL 能不能只扫描索引完成查询。四、用一句话区分 select 和 where 的作用where 后面的字段负责回答怎么找数据 能不能通过索引快速定位 是等值查、范围查还是全表扫所以它主要影响type key rows例如whereid1-constwhereage18-refwhereage18-rangewherename张三且 name 无索引-ALLselect 后面的字段负责回答找到数据后需要取哪些列 这些列索引里有没有 需不需要回表所以它主要影响Extra 是否 Using index 是否回表 有时候也会让 type 从 ALL 变成 index例如selectagefromuser;如果age有索引可以只扫索引type index Extra Using index但select*fromuser;可能只能扫全表type ALL五、你可以这样判断 type以后你看type可以按这个顺序想第一步where / join 条件有没有索引没有索引大概率type ALL有索引继续看。第二步用的是主键还是唯一索引whereid1如果id是主键type constJOIN 中如果用主键/唯一索引关联type eq_ref第三步用的是普通索引等值查询whereage18如果age是普通索引type ref第四步用的是索引范围查询whereage18whereagebetween18and30whereagein(...)可能是type range第五步没有 where但 select 的字段都在索引里selectagefromuser;如果age有索引type index表示扫描整棵索引树。第六步什么索引都用不上select*fromuser;select*fromuserwherename张三;-- name 无索引大概率type ALL表示全表扫描。六、举一个完整对比假设user(idintprimarykey,namevarchar(50),ageint,cityvarchar(50),indexidx_age(age),indexidx_age_name(age,name))例 1select*fromuserwhereid1;分析where id 1 id 是主键 最多一条数据所以type const例 2select*fromuserwhereage18;分析where age 18 age 是普通索引 可能有多行所以type ref例 3select*fromuserwhereage18;分析where age 18 age 是索引 范围查询所以type range例 4select*fromuserwherecity北京;分析city 没有索引 无法快速定位所以type ALL例 5selectagefromuser;分析没有 where 但是 age 在 idx_age 索引里 只需要扫描索引即可所以type index Extra Using index例 6select*fromuser;分析没有 where select * 需要所有字段 不能只靠普通索引完成所以type ALL七、最容易混淆的点你可能疑惑的是selectagefromuser;这里明明没有where为什么type还能是index因为type index不是“根据索引查某几条数据”而是扫描整棵索引树。它不是精确查找只是扫描对象从“表”变成了“索引”。所以type index并不一定特别优秀。它只是比type ALL通常好一些。八、最终总结type本质看的是MySQL 访问这张表的方式。一般情况下where / join 条件决定 MySQL 能不能快速定位数据所以主要影响 type。但是select 后面的字段决定 MySQL 要取哪些列如果这些列都在索引里MySQL 可能只扫描索引所以有时也会影响 type。你可以记成where 决定怎么找 select 决定找完以后取什么 type 反映最终怎么访问表。最常见判断主键等值查询 - const 唯一索引 JOIN - eq_ref 普通索引等值查询 - ref 索引范围查询 - range 扫描整个索引 - index 扫描整张表 - ALL