1. DISTICT优化
MySQL支持对于DISTINCT的优化,下面通过示例具体说明。
示例1 MySQL支持对于DISTINCT消除的优化技术。
沿用14.1.8节示例4的用例,在有主键的e1列上执行DISTINCT,查询执行计划如下:
mysql> EXPLAIN SELECT DISTINCT e1 FROM E;
+----+-------------+-------+-------+------+-------------+
| id | select_type | table | type | key | Extra |
+----+-------------+-------+-------+------+-------------+
| 1 | SIMPLE | E | index | e2 | Using index |
+----+-------------+-------+-------+------+-------------+
1 row in set (0.00 sec)
从查询执行计划看,在表E上执行索引扫描(type列的值为index),用以完成去重的任务。这表明MySQL利用索引这个特性对DISTINCT进行优化(注意,索引扫描的过程中MySQL没有使用主键索引而是选择了e2列上的索引)。
示例2 MySQL不支持对于DISTINCT推入的优化技术。
例如a2列是唯一列,又处于反半连接的语义(NOT EXISTS),完全可以把DISTINCT下推到表t_o2中先执行,然后再执行反半连接操作,查询执行计划如下:
mysql> EXPLAIN EXTENDED SELECT DISTINCT b1 FROM t_o1 WHERE NOT EXISTS (SELECT 1 FROM t_o2 WHERE b1=a2);
+----+--------------------+-------+------+------+------------------------------+
| id | select_type | table | type | key | Extra |
+----+--------------------+-------+------+------+------------------------------+
| 1 | PRIMARY | t_o1 | ALL | NULL | Using where; Using temporary |
| 2 | DEPENDENT SUBQUERY | t_o2 | ref | a2 | Using index |
+----+--------------------+-------+------+------+------------------------------+
2 rows in set, 2 warnings (0.02 sec)
被查询优化器处理后的语句为:
/* select#1 */ select distinct `tt2`.`t_o1`.`b1` AS `b1`
from `tt2`.`t_o1`
where (
not(exists(
/* select#2 */ select 1
from `tt2`.`t_o2`
where (`tt2`.`t_o1`.`b1` = `tt2`.`t_o2`.`a2`)
))
)
从查询执行计划看,表t_o1上使用了临时文件进行DISTINCT操作,而子查询存在没有被消除,这表明DISTINCT操作没有被推入到表t_o2中先执行,所以MySQL不支持DISTINCT推入技术。
示例3 MySQL支持对于DISTINCT迁移的优化技术。
例如a1、a2列是唯一列,查询执行计划如下:
mysql> EXPLAIN EXTENDED SELECT DISTINCT * FROM t_o1, t_o2 WHERE a1=a2;
+----+-------------+-------+------+------+------------------------------+
| id | select_type | table | type | key | Extra |
+----+-------------+-------+------+------+------------------------------+
| 1 | SIMPLE | t_o1 | ALL | NULL | Using where; Using temporary |
| 1 | SIMPLE | t_o2 | ref | a2 | NULL |
+----+-------------+-------+------+------+------------------------------+
2 rows in set, 1 warning (0.00 sec)