“MySQL 优化:优化 SQL 语句:优化 SELECT 语句”的版本间差异
跳到导航
跳到搜索
(建立内容为“category:MySQL == 关于 == 查询以“SELECT”语句的形式执行数据库中的所有查找操作。 * 除了“SELECT”语句外,查询的调整技…”的新页面) |
|||
第21行: | 第21行: | ||
# 处理'''锁'''问题,其中其他会话同时访问表可能会影响查询速度。 | # 处理'''锁'''问题,其中其他会话同时访问表可能会影响查询速度。 | ||
== WHERE | == WHERE 子句优化【适用于“SELECT”、“DELETE”和“UPDATE”语句中的“WHERE”子句】== | ||
您可能会试图重写查询以加快算术运算,同时牺牲可读性。 | |||
* 因为'''MySQL会自动进行类似的优化''',所以通常可以避免这项工作,并以更易于理解和维护的形式保留查询。 | |||
MySQL 执行的一些优化如下: | |||
# 删除不必要的括号: | |||
#: <syntaxhighlight lang="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) | |||
</syntaxhighlight> | |||
# 常数折叠: | |||
#: <syntaxhighlight lang="mysql"> | |||
(a<b AND b=c) AND a=5 | |||
-> b>5 AND b=c AND a=5 | |||
</syntaxhighlight> | |||
# 常数条件移除: | |||
#: <syntaxhighlight lang="mysql"> | |||
(b>=5 AND b=5) OR (b=6 AND 5=5) OR (b=7 AND 5=6) | |||
-> b=5 OR b=6 | |||
</syntaxhighlight> | |||
# 索引使用的常量表达式仅计算一次。 | |||
# '''“COUNT(*)”:在没有“WHERE”单表上,是直接从 MyISAM 和 MEMORY 表的表信息中检索的。''' | |||
#* 当其仅与一个表一起使用时,对于任何“NOT NULL”表达式也将执行此操作。 | |||
# 早期检测无效常量表达式。MySQL很快检测到一些“SELECT”语句是不可能的,并且不返回任何行。 | |||
# '''如果不使用“GROUP BY”或集合函数(“COUNT()”、“MIN()”等),“HAVING”将与“WHERE”合并'''。 | |||
# 对于联接中的每个表,构造一个'''更简单的“WHERE”'''来快速计算表的“WHERE”,并尽快跳过行。 | |||
# 在查询中的所有其他表之前,首先读取所有'''常量表'''。常量表可以是以下任意一个:【???】 | |||
## 空表或具有一行的表。 | |||
## 在“主键”或“唯一索引”上使用“WHERE”子句的表,其中所有索引部分都与常量表达式进行比较,并定义为“NOT NULL”。【?】 | |||
#: 以下所有表均用作常量表: | |||
#: <syntaxhighlight lang="mysql"> | |||
SELECT * FROM t WHERE primary_key=1; | |||
SELECT * FROM t1,t2 | |||
WHERE t1.primary_key=1 AND t2.primary_key=t1.id; | |||
</syntaxhighlight> | |||
# 通过尝试所有可能的方法,找到用于联接表的最佳联接组合。'''如果“ORDER BY”和“GROUP BY”子句中的所有列都来自同一表,则在联接时优先使用该表。''' | |||
# 如果有一个“ORDER BY”子句和另一个“GROUP BY”子句,或者“ORDER BY”或“GROUP BY”包含联接队列中第一个表以外的表中的列,则会创建一个临时表。【???】 | |||
# 如果使用“'''SQL_SMALL_RESULT'''”修饰符,则 MySQL 使用内存中的临时表。【???】 | |||
# 查询每个表索引,并使用'''最佳索引''',除非优化程序认为使用全表扫描更有效。同时,使用扫描是基于最佳索引是否跨越了表的 30%以上,但是固定百分比不再决定使用索引还是扫描。现在,优化器更加复杂,其评估基于其他因素,例如表大小,行数和 I/O 块大小。 | |||
# 在输出每一行之前,将跳过与“HAVING”子句不匹配的行。 | |||
快速查询示例: | |||
<syntaxhighlight lang="mysql"> | |||
SELECT COUNT(*) FROM tbl_name; | |||
SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name; | |||
SELECT MAX(key_part2) FROM tbl_name | |||
WHERE key_part1=constant; | |||
SELECT ... FROM tbl_name | |||
ORDER BY key_part1,key_part2,... LIMIT 10; | |||
SELECT ... FROM tbl_name | |||
ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10; | |||
</syntaxhighlight> | |||
假设索引列是数字,MySQL 仅使用索引树来解析以下查询: | |||
<syntaxhighlight lang="mysql"> | |||
SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val; | |||
SELECT COUNT(*) FROM tbl_name | |||
WHERE key_part1=val1 AND key_part2=val2; | |||
SELECT key_part2 FROM tbl_name GROUP BY key_part1; | |||
</syntaxhighlight> | |||
以下查询使用索引来按排序 Sequences 检索行,而无需单独的排序遍历: | |||
<syntaxhighlight lang="mysql"> | |||
SELECT ... FROM tbl_name | |||
ORDER BY key_part1,key_part2,... ; | |||
SELECT ... FROM tbl_name | |||
ORDER BY key_part1 DESC, key_part2 DESC, ... ; | |||
</syntaxhighlight> | |||
== 范围优化 == | == 范围优化 == |
2021年4月25日 (日) 13:36的版本
关于
查询以“SELECT”语句的形式执行数据库中的所有查找操作。
- 除了“SELECT”语句外,查询的调整技术还适用于:“CREATE TABLE...AS SELECT”,“INSERT INTO...SELECT”和“DELETE”语句中的“WHERE”子句。这些语句还有其他性能方面的考虑,因为它们将写操作与面向读取的查询操作结合在一起。
- NDB Cluster 支持 join 下推优化,将符合条件的 join 整体发送到 NDB Cluster 数据节点,在这些节点之间可以分布并并行执行。【???】
优化查询的主要注意事项是:
- 要使慢速“SELECT ... WHERE”查询更快,首先要检查的是是否可以添加index。在“WHERE”子句中使用的列上设置索引,以加快评估,过滤和最终检索结果的速度。为了避免浪费磁盘空间,请构造一小组索引,以加快应用程序中使用的许多相关查询的速度。
- 对于使用“joins”和“foreign keys”之类的功能引用不同表的查询,索引尤为重要。您可以使用“EXPLAIN”语句来确定 SELECT 使用哪些索引。
- 隔离并调整查询中花费时间过多的任何部分,例如函数调用。根据查询的结构方式,可以对结果集中的每一行调用一次函数,甚至可以对表中的每一行调用一次函数,从而极大地提高了效率。
- 最小化查询中的全表扫描数量,尤其是对于大表。
- 通过定期使用“ANALYZE TABLE”语句来使表统计信息保持最新,因此优化器具有构造有效执行计划所需的信息。
- 了解每个表的存储引擎特定的调整技术,索引技术和配置参数。InnoDB 和 MyISAM 都有一套准则,用于启用和维持查询的高性能。
- 避免以难以理解的方式转换查询,尤其是在优化程序自动执行某些相同转换的情况下。【?】
- 如果使用基本准则之一不能轻松解决性能问题,请通过阅读“EXPLAIN”计划并调整索引,WHERE 子句,join 子句等来调查特定查询的内部详细信息。
- (当您达到一定的专业水平时,阅读 EXPLAIN 计划可能是每个查询的第一步。)【!】
- 调整 MySQL 用于缓存的内存区域的大小和属性。通过有效地使用InnoDB buffer pool(缓冲池),MyISAM 键高速缓存和 MySQL 查询高速缓存,重复查询的运行速度更快,因为第二次及以后都从内存中检索结果。
- 即使对于使用缓存区域快速运行的查询,您也可能会进一步优化,以使它们需要更少的缓存,从而使您的应用程序更具可伸缩性。可伸缩性意味着您的应用程序可以处理更多的并发用户,更大的请求等,而不会导致性能大幅下降。
- 处理锁问题,其中其他会话同时访问表可能会影响查询速度。
WHERE 子句优化【适用于“SELECT”、“DELETE”和“UPDATE”语句中的“WHERE”子句】
您可能会试图重写查询以加快算术运算,同时牺牲可读性。
- 因为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
- 索引使用的常量表达式仅计算一次。
- “COUNT(*)”:在没有“WHERE”单表上,是直接从 MyISAM 和 MEMORY 表的表信息中检索的。
- 当其仅与一个表一起使用时,对于任何“NOT NULL”表达式也将执行此操作。
- 早期检测无效常量表达式。MySQL很快检测到一些“SELECT”语句是不可能的,并且不返回任何行。
- 如果不使用“GROUP BY”或集合函数(“COUNT()”、“MIN()”等),“HAVING”将与“WHERE”合并。
- 对于联接中的每个表,构造一个更简单的“WHERE”来快速计算表的“WHERE”,并尽快跳过行。
- 在查询中的所有其他表之前,首先读取所有常量表。常量表可以是以下任意一个:【???】
- 空表或具有一行的表。
- 在“主键”或“唯一索引”上使用“WHERE”子句的表,其中所有索引部分都与常量表达式进行比较,并定义为“NOT NULL”。【?】
- 以下所有表均用作常量表:
SELECT * FROM t WHERE primary_key=1; SELECT * FROM t1,t2 WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
- 通过尝试所有可能的方法,找到用于联接表的最佳联接组合。如果“ORDER BY”和“GROUP BY”子句中的所有列都来自同一表,则在联接时优先使用该表。
- 如果有一个“ORDER BY”子句和另一个“GROUP BY”子句,或者“ORDER BY”或“GROUP BY”包含联接队列中第一个表以外的表中的列,则会创建一个临时表。【???】
- 如果使用“SQL_SMALL_RESULT”修饰符,则 MySQL 使用内存中的临时表。【???】
- 查询每个表索引,并使用最佳索引,除非优化程序认为使用全表扫描更有效。同时,使用扫描是基于最佳索引是否跨越了表的 30%以上,但是固定百分比不再决定使用索引还是扫描。现在,优化器更加复杂,其评估基于其他因素,例如表大小,行数和 I/O 块大小。
- 在输出每一行之前,将跳过与“HAVING”子句不匹配的行。
快速查询示例:
SELECT COUNT(*) FROM tbl_name;
SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
SELECT MAX(key_part2) FROM tbl_name
WHERE key_part1=constant;
SELECT ... FROM tbl_name
ORDER BY key_part1,key_part2,... LIMIT 10;
SELECT ... FROM tbl_name
ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;
假设索引列是数字,MySQL 仅使用索引树来解析以下查询:
SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;
SELECT COUNT(*) FROM tbl_name
WHERE key_part1=val1 AND key_part2=val2;
SELECT key_part2 FROM tbl_name GROUP BY key_part1;
以下查询使用索引来按排序 Sequences 检索行,而无需单独的排序遍历:
SELECT ... FROM tbl_name
ORDER BY key_part1,key_part2,... ;
SELECT ... FROM tbl_name
ORDER BY key_part1 DESC, key_part2 DESC, ... ;