explain select * from t1 join t2;
一、性能按type排序
system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
二、性能按Extra排序
Using index:用了覆盖索引
Using index condition:用了条件索引(索引下推)
Using where:从索引查出来数据后继续用where条件过滤
Using join buffer (Block Nested Loop):join的时候利用了join buffer(优化策略:去除外连接、增大join buffer大小)
Using filesort:用了文件排序,排序的时候没有用到索引
Using temporary:用了临时表(优化策略:增加条件以减少结果集、增加索引,思路就是要 么减少待排序的数量,要么就提前排好序)
Start temporary, End temporary:子查询的时候,可以优化成半连接,但是使用的是通过临时表来去重
FirstMatch(tbl_name):子查询的时候,可以优化成半连接,但是使用的是直接进行数据比较来去重
三、常见的优化手段
SQL语句中IN包含的值不应过多,不能超过200个,200个以内查询优化器计算成本时比较精准,超过200个是估算的成本,另外建议能用between就不要用in,这样就可以使用range索引了。
SELECT语句务必指明字段名称:SELECT * 增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前断也需要更新。所以要求直接在select后面接上字段名。
当只需要一条数据的时候,使用limit 1
排序时注意是否能用到索引
使用or时如果没有用到索引,可以改为union all 或者union
如果in不能用到索引,可以改成exists看是否能用到索引
使用合理的分页方式以提高分页的效率
不建议使用%前缀模糊查询
避免在where子句中对字段进行表达式操作
避免隐式类型转换
对于联合索引来说,要遵守最左前缀法则
必要时可以使用force index来强制查询走某个索引
对于联合索引来说,如果存在范围查询,比如between,>,<等条件时,会造成后面的索引字段失效。
尽量使用inner join,避免left join,让查询优化器来自动选择小表作为驱动表
必要时刻可以使用straight_join来指定驱动表,前提条件是本身是inner join
四、type 访问方法
- system
当表中只有一条记录并且该表使用的存储引擎的统计数据是精确的,比如MyISAM、Memory,那么对该表的访问方法就是system。 - const
当我们根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是const。 - eq_ref
在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则对该被驱动表的访问方法就是eq_re - ref
当通过普通的二级索引列与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是ref。 - ref_or_null
当对普通二级索引进行等值匹配查询,该索引列的值也可以是NULL值时,那么对该表的访问方法就可能是ref_or_null - index_merge
索引合并 - unique_subquery
如果查询优化器决定将IN子查询转换为EXISTS子查询,而且子查询可以使用到主键进行等值匹配的话,那么该子查询执行计划的type列的值就是unique_subquery。 - index_subquery
index_subquery与unique_subquery类似,只不过访问子查询中的表时使用的是普通的索引。 - range
- index
当我们可以使用覆盖索引,但需要扫描全部的索引记录时,该表的访问方法就是index。 - ALL
全表扫描
五、Extra
Extra列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。
- No tables used
当查询语句的没有FROM子句时将会提示该额外信息。 - Impossible WHERE
查询语句的WHERE子句永远为FALSE时将会提示该额外信息。 - No matching min/max row
当查询列表处有MIN或者MAX聚集函数,但是并没有符合WHERE子句中的搜索条件的记录时,将会提示该额外信息。 - Using index
当我们的查询列表以及搜索条件中只包含属于某个索引的列,也就是在可以使用索引覆盖的情况下,在Extra列将会提示该额外信息。 - Using index condition
有些搜索条件中虽然出现了索引列,但却不能使用到索引(在MySQL 5.6版本后加入的新特性) - Using where
当我们使用全表扫描来执行对某个表的查询,并且该语句的WHERE子句中有针对该表的搜索条件时,在Extra列中会提示上述额外信息。 - Using join buffer (Block Nested Loop)
在连接查询执行过程中,当被驱动表不能有效的利用索引加快访问速度,MySQL一般会为其分配一块名叫join buffer的内存块来加快查询速度。 - Using filesort
很多情况下排序操作无法使用到索引,只能在内存中(记录较少的时候)或者磁盘中(记录较多的时候)进行排序,这种在内存中或者磁盘上进行排序的方式统称为文件排序(英文名:filesort)。如果某个查询需要使用文件排序的方式执行查询,就会在执行计划的Extra列中显示Using filesort提示。 - Using temporary
在许多查询的执行过程中,MySQL可能会借助临时表来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含DISTINCT、GROUP BY、UNION等子句的查询过程中,如果不能有效利用索引来完成查询,MySQL很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行计划的Extra列将会显示Using temporary提示。 - Start temporary、End temporary
查询优化器会优先尝试将IN子查询转换成semi-join,而semi-join又有好多种执行策略,当执行策略为DuplicateWeedout时,也就是通过建立临时表来实现为外层查询中的记录进行去重操作时,驱动表查询执行计划的Extra列将显示Start temporary提示,被驱动表查询执行计划的Extra列将显示End temporary提示 - FirstMatch(表名)
在将In子查询转为semi-join时,如果采用的是FirstMatch执行策略,则在被驱动表执行计划的Extra列就是显示FirstMatch(tbl_name)提示。
以上均为鲁班学院学习资料,欢迎大家报班学习,真心推荐