针对官方文档的翻译,并加入一些比较难理解的补充说明,以下为译文:
注:该文档的意思是以下优化正常情况是由mysql自动优化,即不用刻意优化。
本节讨论可以如何处理查询语句WHERE子句的优化。这些示例使用 SELECT语句,但是对DELETE和UPDATE 语句中的WHERE子句也可以进行相同的优化。
您可能会想优化sql查询以使查询效率更快,但是优化的同时又牺牲了可读性。由于MySQL自动进行类似的优化,因此您通常可以避免这项工作,而将查询保留为更易于理解和维护的形式。MySQL自动执行的一些优化如下:
- 删除不必要的括号
((a AND b) AND c OR (((a AND b) AND (c AND d))))
优化后->
(a AND b AND c) OR (a AND b AND c AND d)
- 恒定条件优化
(a<b AND b=c) AND a=5
优化后->
b>5 AND b=c AND a=5
(b>=5 AND b=5) OR (b=6 AND 5=5) OR (b=7 AND 5=6)
优化后->
b=5 OR b=6
- 索引使用的常量表达式仅计算一次。
优化程序可以解析为常量的任何表达式都被解析为常量,而不是针对每一行进行求值。
WHERE start_date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
如果今天运行,该查询将完全等同于
WHERE start_date >= '2018-04-25'
所以不需要每次都计算,mysql会自动计算出值再使用常量比较
- 使用COUNT(*)查询如果没有Where语句,那么是从MyISAM 和MEMORY表的table信息中检索。当count与仅一个 table 一起使用时,也可以对任何NOT NULL表达式执行此操作。
- 如果不使用GROUP BY或聚合函数(COUNT(),MIN()等),则HAVING与WHERE合并。
- 对于联接中的每个表,使用WHERE构造一个简单的表以获得表的快速评估,并尽快跳过行。
个人理解:在使用多表联表查询的时候
1、执行FROM语句(以基准表做笛卡尔积)
2、执行ON过滤
3、添加外部行
4、执行where条件过滤
5、执行group by分组语句
6、执行having
7、select列表
8、执行distinct去重复数据
9、执行order by字句
10、执行limit字句
所以来说,如果是大表联表查询,mysql会把步骤4提前,先用where过滤数据,再用join联表查询
select * from table1 a left join table2 b on a.id=b.id where a.type=xxxxx and b.type=xxxxx
等同于:
select * from
(select * from table1 where type=xxx) a
left join
(select * from table2 where type=xxx) b
on a.id =b.id
- 在查询中的任何其他表之前,首先读取所有常量表。常量表可以是以下任意一个:
(All constant tables are read first before any other tables in the query. A constant table is any of the following:)- 空表或具有一行的表(An empty table or a table with one row.)。
- 与PRIMARY 或UNIQUE 索引WHERE 上的子句一起使用的表,其中所有索引部分都与常量表达式进行比较,并定义为 NOT NULL(A table that is used with a WHERE clause on a PRIMARY KEY or a UNIQUE index, where all index parts are compared to constant expressions and are defined as NOT NULL)
这里直翻不太顺,这个大概意思是可以常量查询(一行,或者带索引的查询)mysql会优先放在前面执行
常量查询即如下:
SELECT * FROM t WHERE primary_key=1;
待优化查询:
SELECT * FROM t1,t2
WHERE t2.primary_key=t1.id AND t1.primary_key=1;
mysql自动优化后查询:
SELECT * FROM t1,t2
WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
- 通过尝试所有可能的方法,找到用于联接表的最佳联接组合。如果ORDER BYand GROUP BY子句中的所有列 都来自同一表,则在连接时优先把表先查出来。
- 如果存在一个ORDER BY子句和另一个GROUP BY子句,或者如果 ORDER BY或GROUP BY 包含联接队列中第一个表以外的表中的列,则会创建一个临时表。
- 如果使用SQL_SMALL_RESULT 修饰符,MySQL将使用内存中的临时表。
- 查询每个表索引,并使用最佳索引,除非优化程序认为使用全表扫描更有效。曾经,是否使用全表扫描是基于最佳索引是否跨越了表的30%以上来决定的,但是现在,固定百分比不再决定使用索引还是扫描。现在的优化器更加复杂,其估计基于其他因素,例如表大小,行数和I / O块大小。
- 在某些情况下,MySQL甚至无需查询数据文件就可以从索引中读取行。如果索引中使用的所有列都是数字列,则仅索引树用于解析查询。
- 在输出每一行之前,HAVING将跳过不匹配该子句的那些行 。
网友评论