接续上一篇:
MySQL子查询优化---目标列中的子查询执行情况分析
http://blog.163.com/li_hx/blog/static/18399141320154291133386/
7
mysql> select (select max(a) from t as t2) from t as t1;
+------------------------------+
| (select max(a) from t as t2) |
+------------------------------+
| 2 |
| 2 |
+------------------------------+
问题就这样又来了:究竟这个示例中的子查询,会被执行几次?
回到上一篇的标题5,我们给出了一个循环算法,用蓝色字体说明了“子查询返回的结果有多行”的情况,在这种情况下MySQL将报告错误。
而第7条中给出的是相对于第5条中的示例改造后的例子,差别在于第7条满足了“目标列中的子查询需是标量子查询的要求”。
因为第7条中的示例不满足退出条件,所以,我们可以推知,子查询一定会执行2次,这是因为t1中有2条元组。
但是,真正的答案是:此示例中的子查询只被执行了一次。
为什么?
仔细观察子查询,select max(a) from t as t2,除了和父查询都基于同一个表t外,2者之间没有其他关系。
数据库中有相关子查询和非相关子查询的概念,《数据库查询优化器的艺术》一书P19给出它们的含义,如下图:
相关子查询,有另外名字,叫做“重复子查询”,意思是在执行过程中,子查询依靠外部查询获得值。这意味着子查询是重复执行的,为外部查询可能选择的每一行均执行一次。
而非相关子查询,就可叫做“非重复子查询”,意思是执行一次即可。
所以,本示例“子查询只被执行了一次”就不难理解,因为本示例给出的是一个“目标列中出现的是非相关子查询”。
MySQL的执行器,把这个“非相关子查询”的结果缓存了起来,所以这个子查询就不需要因父表的元组数而被多次执行了。
8 相关子查询的例子
注意where子句,“t2.a=t1.b”使得t1和t2建立了关系。这就是相关子查询。
mysql> select (select max(a) from t as t2 where t2.a=t1.b) as MAX, t1.* from t as t1;
+------+------+------+
| MAX | a | b |
+------+------+------+
| 1 | 1 | 1 | <--b值为1,使得子查询执行一次,得出结果为1
| 2 | 2 | 2 | <--b值为2,使得子查询执行一次,得出结果为2
+------+------+------+
2 rows in set (0.01 sec)
子查询的结果受到父表的变量的影响,其结果不同,不存在被缓存的可能。
mysql> explain select (select max(a) from t as t2 where t2.a=t1.b) as MAX, t1.* from t as t1;
+----+--------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | PRIMARY | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
| 2 | DEPENDENT SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
+----+--------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
2 rows in set, 2 warnings (0.01 sec)
"说明: DEPENDENT SUBQUERY",表示依赖关系,存在关联关系的 相关子查询,会被嵌套执行.
9 推广
思考问题:如果子查询不是在目标列,而是在FROM子句中,情况又会怎么样?
答案与此(此,指代"目标列中的子查询执行情况")相同,原因请思考.