This section discusses optimizations that can be made for processing 本节讨论可用于处理WHERE
clauses. WHERE
子句的优化。The examples use 这些示例使用SELECT
statements, but the same optimizations apply for WHERE
clauses in DELETE
and UPDATE
statements.SELECT
语句,但DELETE
和UPDATE
语句中的WHERE
子句也采用相同的优化。
Because work on the MySQL optimizer is ongoing, not all of the optimizations that MySQL performs are documented here.因为MySQL优化器的工作正在进行中,这里并没有记录MySQL执行的所有优化。
You might be tempted to rewrite your queries to make arithmetic operations faster, while sacrificing readability. 您可能会试图重写查询以加快算术运算,同时牺牲可读性。Because MySQL does similar optimizations automatically, you can often avoid this work, and leave the query in a more understandable and maintainable form. 因为MySQL会自动进行类似的优化,所以通常可以避免这项工作,并以更易于理解和维护的形式保留查询。Some of the optimizations performed by MySQL follow:MySQL执行的一些优化如下:
Removal of unnecessary parentheses:删除不必要的括号:
((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)
Constant folding:连续折叠:
(a<b AND b=c) AND a=5 -> b>5 AND b=c AND a=5
Constant condition removal:恒定条件移除:
(b>=5 AND b=5) OR (b=6 AND 5=5) OR (b=7 AND 5=6) -> b=5 OR b=6
In MySQL 8.0.14 and later, this takes place during preparation rather than during the optimization phase, which helps in simplification of joins. 在MySQL 8.0.14及更高版本中,这发生在准备阶段而不是优化阶段,这有助于简化连接。See Section 8.2.1.9, “Outer Join Optimization”, for further information and examples.有关更多信息和示例,请参阅第8.2.1.9节“外部连接优化”。
Constant expressions used by indexes are evaluated only once.索引使用的常量表达式只计算一次。
Beginning with MySQL 8.0.16, comparisons of columns of numeric types with constant values are checked and folded or removed for invalid or out-of-rage values:从MySQL 8.0.16开始,检查数值类型的列与常量值的比较,并折叠或删除无效或超出范围的值:
# CREATE TABLE t (c TINYINT UNSIGNED NOT NULL); SELECT * FROM t WHERE c ≪ 256; -≫ SELECT * FROM t WHERE 1;
See Section 8.2.1.14, “Constant-Folding Optimization”, for more information.详见第8.2.1.14节,“恒定折叠优化”。
不带COUNT(*)
on a single table without a WHERE
is retrieved directly from the table information for MyISAM
and MEMORY
tables. WHERE
的单个表上的COUNT(*)
直接从MyISAM和内存表的表信息中检索。This is also done for any 当只与一个表一起使用时,也会对任何NOT NULL
expression when used with only one table.NOT NULL
表达式执行此操作。
Early detection of invalid constant expressions. 早期检测无效常量表达式。MySQL quickly detects that some MySQL很快检测到一些SELECT
statements are impossible and returns no rows.SELECT
语句是不可能的,并且不返回任何行。
如果不使用HAVING
is merged with WHERE
if you do not use GROUP BY
or aggregate functions (COUNT()
, MIN()
, and so on).GROUP BY
或聚焦函数(COUNT()
、MIN()
等),HAVING
将与WHERE
合并。
For each table in a join, a simpler 对于联接中的每个表,构造一个更简单的WHERE
is constructed to get a fast WHERE
evaluation for the table and also to skip rows as soon as possible.WHERE
来快速计算表的WHERE
,并尽快跳过行。
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.空表或只有一行的表。
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
.WHERE
子句一起使用的一种表,其中所有索引部分都与常量表达式进行比较,并定义为NOT NULL
。
All of the following tables are used as constant tables:以下所有表格都用作常量表格:
SELECT * FROM t WHEREprimary_key
=1; SELECT * FROM t1,t2 WHERE t1.primary_key
=1 AND t2.primary_key
=t1.id;
The best join combination for joining the tables is found by trying all possibilities. 通过尝试各种可能性,可以找到连接表的最佳连接组合。If all columns in 如果ORDER BY
and GROUP BY
clauses come from the same table, that table is preferred first when joining.ORDER BY
和GROUP BY
子句中的所有列都来自同一个表,则在联接时首选该表。
If there is an 如果存在ORDER BY
clause and a different GROUP BY
clause, or if the ORDER BY
or GROUP BY
contains columns from tables other than the first table in the join queue, a temporary table is created.ORDER BY
子句和不同的GROUP BY
子句,或者ORDER BY
或GROUP BY
包含联接队列中第一个表以外的表中的列,则会创建一个临时表。
If you use the 如果您使用SQL_SMALL_RESULT
modifier, MySQL uses an in-memory temporary table.SQL_SMALL_RESULT
修饰符,MySQL将使用内存中的临时表。
Each table index is queried, and the best index is used unless the optimizer believes that it is more efficient to use a table scan. 查询每个表索引,并使用最佳索引,除非优化器认为使用表扫描更有效。At one time, a scan was used based on whether the best index spanned more than 30% of the table, but a fixed percentage no longer determines the choice between using an index or a scan. 有一次,扫描是基于最佳索引是否跨越表的30%以上而使用的,但固定的百分比不再决定使用索引还是扫描的选择。The optimizer now is more complex and bases its estimate on additional factors such as table size, number of rows, and I/O block size.现在,优化器更加复杂,它的估计基于其他因素,如表大小、行数和I/O块大小。
In some cases, MySQL can read rows from the index without even consulting the data file. 在某些情况下,MySQL甚至不需要查阅数据文件就可以从索引中读取行。If all columns used from the index are numeric, only the index tree is used to resolve the query.如果索引中使用的所有列都是数字,则只有索引树用于解析查询。
Before each row is output, those that do not match the 在输出每一行之前,将跳过那些与HAVING
clause are skipped.HAVING
子句不匹配的行。
Some examples of queries that are very fast:一些非常快速的查询示例:
SELECT COUNT(*) FROMtbl_name
; SELECT MIN(key_part1
),MAX(key_part1
) FROMtbl_name
; SELECT MAX(key_part2
) FROMtbl_name
WHEREkey_part1
=constant
; SELECT ... FROMtbl_name
ORDER BYkey_part1
,key_part2
,... LIMIT 10; SELECT ... FROMtbl_name
ORDER BYkey_part1
DESC,key_part2
DESC, ... LIMIT 10;
MySQL resolves the following queries using only the index tree, assuming that the indexed columns are numeric:MySQL仅使用索引树解析以下查询,假设索引列为数字:
SELECTkey_part1
,key_part2
FROMtbl_name
WHEREkey_part1
=val
; SELECT COUNT(*) FROMtbl_name
WHEREkey_part1
=val1
ANDkey_part2
=val2
; SELECTkey_part2
FROMtbl_name
GROUP BYkey_part1
;
The following queries use indexing to retrieve the rows in sorted order without a separate sorting pass:以下查询使用索引按排序顺序检索行,无需单独的排序过程:
SELECT ... FROMtbl_name
ORDER BYkey_part1
,key_part2
,... ; SELECT ... FROMtbl_name
ORDER BYkey_part1
DESC,key_part2
DESC, ... ;