以前一直以为数据库在做子查询时会重新做全部的查询,后来发现postgresql在做子查询时如果
来自父查询的参数未发生改变,那么其是可以直接计算结果而不用再次执行子查询的,那么mysql是怎么
处理的呢,再次翻出mysql(5.6.10)的源码简单调试了下发现以下结论:
1. 在执行子查询无关的exists not exists时如:select * from a where exists(select * from b);那么在执
行Join::optimize函数时将自动执行子查询select * from b得到结果作为a扫描的条件,虽然呈现的执行
计划如下:
对于类似于select * from a where a > all(select * from b);这里其查询计划如下:
其中的select * from b的结果将会被缓存起来,下次执行子查询时可以直接取出子查询的结果.
这是因为如下代码的作用:
subselect_single_select_engine::exec
if (select_lex->uncacheable &&
select_lex->uncacheable != UNCACHEABLE_EXPLAIN
&& executed)
{
join->reset();
item->reset();
item->assigned((executed= 0));
}
这里如果已经执行过的子查询不可缓存则不缓存结果.这里的uncacheable取值为如下:
// uncachable cause
#define UNCACHEABLE_DEPENDENT 1
#define UNCACHEABLE_RAND 2
#define UNCACHEABLE_SIDEEFFECT 4
/// forcing to save JOIN for explain
#define UNCACHEABLE_EXPLAIN 8
/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
#define UNCACHEABLE_UNITED 16
#define UNCACHEABLE_CHECKOPTION 32
这里UNCACHEABLE_DEPENDENT明显在说明dependent子查询计划是不可缓存的,
其它几个类型不清楚啥作用.在调试select * from a where a > all(select * from b)时发
现select * from b 这个子查询的优化发生在其具体执行的时候,这倒是和postgresql不同,
postgresql在执行计划前完成了所有节点的计划与优化.另外对于子查询中存在group这
种语句时postgresql不能提升子查询但是mysql却可以,mysql会将父节点的结果存入一
个join buffer,然后和子查询做连接而不像postgresql那样对于nest loop join先外节点后
内节点的扫描.