本节讨论可以对处理WHERE子句进行的优化。这些示例使用SELECT语句,但同样的优化也适用于DELETE和UPDATE语句中的WHERE子句
您可能会试图重写查询以使算术运算更快,同时牺牲可读性。由于MySQL会自动执行类似的优化,因此您通常可以避免这项工作,并将查询保持在更易于理解和维护的形式。MySQL执行的一些优化如下:
索引使用的常量表达式只计算一次。
不带WHERE的单个表上的COUNT(*)直接从MyISAM和MEMORY表的表信息中检索。当仅与一个表一起使用时,也可以对任何NOT NULL表达式执行此操作。
早期检测无效的常量表达式。MySQL很快检测到某些SELECT语句是不可能的,并且不返回任何行。
如果不使用GROUP BY或聚合函数(COUNT()、MIN()等),HAVING将与WHERE合并。
对于联接中的每个表,构造一个更简单的WHERE,以快速计算表的WHERE,并尽快跳过行。
所有常量表都会在查询中的任何其他表之前首先读取。常数表可以是以下任何一种:
空表或只有一行的表。
与PRIMARY KEY或UNIQUE索引上的WHERE子句一起使用的表,其中所有索引部分都与常量表达式进行比较,并定义为NOT NULL。
以下所有表都用作常量表:
通过尝试所有可能性,找到连接表的最佳连接组合。如果ORDER BY和GROUP BY子句中的所有列都来自同一个表,则连接时首选该表。
如果存在ORDER BY子句和不同的GROUP BY子句,或者ORDER BY或GROUP BY包含联接队列中第一个表以外的表中的列,则会创建一个临时表。
如果您使用了DateTimeSMALL_RESULT修饰符,MySQL将使用内存中的临时表。
查询每个表索引,并使用最佳索引,除非优化器认为使用表扫描更有效。曾经,扫描是基于最佳索引是否覆盖了表的30%以上,但固定的百分比不再决定使用索引还是扫描。优化器现在更加复杂,其估计基于其他因素,如表大小、行数和I/O块大小。
在某些情况下,MySQL甚至可以在不查阅数据文件的情况下从索引中读取行。如果索引中使用的所有列都是数字,则只有索引树用于解析查询。
在输出每一行之前,跳过与HAVING子句不匹配的行。
一些非常快速的查询示例:
MySQL resolves the following queries using only the index tree, assuming that the indexed columns are numeric:
以下查询使用索引按排序顺序检索行,而无需单独的排序过程: