MySQL Explain之“Select tables optimized away”

MySQL Explain之“Select tables optimized away”

今天使用MySQL的时候突发奇想的对select max(id) from t1这种语句用了下explain,在结果里面的Extra里面显示Select tables optimized away。下面的内容摘自MySQL官方文档。

优化器会确定两件事:第一个是至多返回一行;第二个是为了返回第一行,必须读取可确定的一些行。这些行会在优化期间被读取(例如,读取索引),查询期间不需要读取任何表。

第一个条件在查询中有隐式分组的被满足(有聚合函数但是没有GROUP BY子句)。第二个条件在使用索引进行查找的时候满足。读取的索引的数量决定了需要读取的行数。

考虑下面这个隐式分组查询:

SELECT MIN(c1), MIN(c2) FROM t1;

假设MIN(c1)可以通过读取一个索引获得,MIN(c2)可以通过读取另一个索引获得。换句话说,对于列c1,c2都存在一个索引,并且这两个索引的第一列是c1和c2。在这种情况下,读取两个确定的行可返回一个结果。

如果读取的行不确定,那么Extra列不会出现该提示,考虑下面的行:

SELECT MIN(c2) FROM t1 WHERE c1 <= 10;

假设(c1,c2)是覆盖索引,使用这个索引,所有c1 <= 10的行必须被扫描来查找最小的c2。相比之下,看下面的查询:

SELECT MIN(c2) FROM t1 WHERE c1 = 10;

在这种情况下,索引的第一列c1 = 10的列中包含了最小的c2列。只有一行必须被读取来获取返回的行。

对于MyISAM表,每个表里面里面有一个额外的行包含了表中的行数,当执行没有WHERE子句,或者WHERE子句恒定为true,并且没有GROUP BY的COUNT(*)查询的时候,Extra也会出现(这是隐式分组查询的一个实例,存储引擎会影响是否读取确定的行)。

总结,Explain出现这个提示是说明这个查询直接通过扫描索引就能得到。

除了上面例子中的sql,下面这个也可以,c1是索引:

SELECT MIN(c1) FROM t1 WHERE c1 < 30;

还有上面提到的,如果是多列索引(c1,c2),下面第一个sql是可以的,但是聚合函数参数是c2是不行的,这与索引的使用原理是一样的:

SELECT MIN(c1) FROM t1;

-- 这两个是不行的
SELECT MIN(c2) FROM t1;
SELECT MIN(c1), MIN(c2) FROM t1;

(完)