mysql不支持jppd谓词推入,只支持单独的过滤谓词推入到view里,只支持单独过滤谓词推入到 union all视图(mysql8支持)、group by等视图里,
不支持join谓词推入不能merge的视图,比如union all视图,group by视图里
mysql join谓词不能推入到union all视图里,直接materialize化,性能差
可以从代码上看出:
// 下推函数调用点 Query_block::prepare
Query_block::prepare()
apply_local_transforms()
if (outest query block) // 自顶层调用,且内部query block已经自内向外做了前期fix和simplify_joins等操作
push_conditions_to_derived_tables(); // 将条件下推到派生表中
// push_conditions_to_derived_tables 函数
void Query_block::push_conditions_to_derived_tables()
// 遍历每一个物化的派生表
for (auto& derived_table : materialized_derived_tables)
// 如果当前查询块中存在 WHERE 条件
if (this->has_where_condition() && 其他规则检查)
// 从条件中提取只属于该派生表的部分
Condition extracted_condition = extract_cond_for_table(); // 对条件谓词的field进行判断,提取仅属于派生表field的条件
// 检查条件是否可以被下推到窗口函数之后的 HAVING 子句
push_past_window_functions()
// 无法下推的条件仍然保留在外层查询块中
make_remainder_cond()
// 检查条件是否可以进一步下推到 GROUP BY(如果存在)的 WHERE 子句
push_past_group_by()
// 无法下推的条件会成为派生表 HAVING 子句的一部分
remained_conditions->add_items()
// 将下推到派生表的having 和 where 条件做转换并真正附加到派生表查询表达式中(replace + attach)
replace_columns_in_cond()
attach_cond_to_derived()
// 遍历当前查询块中的每一个查询表达式
for (auto& query_expr : query_block)
query_expr.push_conditions_to_derived_tables() // 递归调用,将条件尽可能深地向下推
=================例子
--可以看到,这里的tmp是union all组成的inline viw,与s1关联,s1返回行少,但是不能将s1连接条件下推到inline view里
--在oracle里支持jppd,这是基于CBQT的查询转换,mysql不支持
--那么inline view只能做materialize,这里做的是materialize scan,因为返回行多。。。
点击(此处)折叠或打开
-
explain analyze
-
select * from s1,
-
(
-
select id,info from s2
-
union all
-
select id,info from s3
-
) tmp
-
where s1.id=tmp.id and s1.info=tmp.info and s1.id1 <=50\G
-
*************************** 1. row ***************************
-
EXPLAIN: -> Nested loop inner join (cost=92216.68 rows=9969) (actual time=328.958..1012.322 rows=100 loops=1)
-
-> Filter: (tmp.id is not null) (cost=40148.81..22432.98 rows=199382) (actual time=328.924..428.186 rows=200000 loops=1)
-
-> Table scan on tmp (cost=40148.91..42643.68 rows=199382) (actual time=328.921..412.680 rows=200000 loops=1)
-
-> Union all materialize (cost=40148.90..40148.90 rows=199382) (actual time=328.912..328.912 rows=200000 loops=1)
-
-> Table scan on s2 (cost=10105.35 rows=99691) (actual time=0.024..72.914 rows=100000 loops=1)
-
-> Table scan on s3 (cost=10105.35 rows=99691) (actual time=0.023..75.585 rows=100000 loops=1)
-
-> Filter: ((s1.info = tmp.info) and (s1.id1 <= 50)) (cost=0.25 rows=0.05) (actual time=0.003..0.003 rows=0 loops=200000)
-
-> Index lookup on s1 using idx_s1 (id=tmp.id) (cost=0.25 rows=1) (actual time=0.003..0.003 rows=0 loops=200000)
-
- 1 row in set (1.01 sec)
-- 单独过滤谓词mysql8支持推入到union all视图里
点击(此处)折叠或打开
-
explain analyze
-
select * from s1,
-
(
-
select id,info from s2
-
union all
-
select id,info from s3
-
) tmp where tmp.id<10\G
-
*************************** 1. row ***************************
-
EXPLAIN: -> Inner hash join (no condition) (cost=17274.36 rows=172368) (actual time=0.180..26.708 rows=180000 loops=1)
-
-> Table scan on s1 (cost=54.56 rows=9576) (actual time=0.010..8.718 rows=10000 loops=1)
-
-> Hash
-
-> Table scan on tmp (cost=10.57..13.15 rows=18) (actual time=0.148..0.150 rows=18 loops=1)
-
-> Union all materialize (cost=10.42..10.42 rows=18) (actual time=0.146..0.146 rows=18 loops=1)
-
-> Index range scan on s2 using idx_s2 over (NULL < id < 10), with index condition: (s2.id < 10) (cost=4.31 rows=9) (actual time=0.035..0.062 rows=9 loops=1)
-
-> Index range scan on s3 using idx_s3 over (NULL < id < 10), with index condition: (s3.id < 10) (cost=4.31 rows=9) (actual time=0.019..0.056 rows=9 loops=1)
-
- 1 row in set (0.10 sec)