MySQL不支持view jppd下推

130阅读 0评论2025-04-26 dingjun123
分类:Mysql/postgreSQL

对于不能merge的view/derived table/cte
 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,因为返回行多。。。

点击(此处)折叠或打开

  1. explain analyze
  2. select * from s1,
  3. (
  4. select id,info from s2
  5. union all
  6. select id,info from s3
  7. ) tmp
  8. where s1.id=tmp.id and s1.info=tmp.info and s1.id1 <=50\G
  9. *************************** 1. row ***************************
  10. EXPLAIN: -> Nested loop inner join (cost=92216.68 rows=9969) (actual time=328.958..1012.322 rows=100 loops=1)
  11.     -> Filter: (tmp.id is not null) (cost=40148.81..22432.98 rows=199382) (actual time=328.924..428.186 rows=200000 loops=1)
  12.         -> Table scan on tmp (cost=40148.91..42643.68 rows=199382) (actual time=328.921..412.680 rows=200000 loops=1)
  13.             -> Union all materialize (cost=40148.90..40148.90 rows=199382) (actual time=328.912..328.912 rows=200000 loops=1)
  14.                 -> Table scan on s2 (cost=10105.35 rows=99691) (actual time=0.024..72.914 rows=100000 loops=1)
  15.                 -> Table scan on s3 (cost=10105.35 rows=99691) (actual time=0.023..75.585 rows=100000 loops=1)
  16.     -> 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)
  17.         -> 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)

  18. 1 row in set (1.01 sec)

-- 单独过滤谓词mysql8支持推入到union all视图里

点击(此处)折叠或打开

  1. explain analyze
  2. select * from s1,
  3. (
  4. select id,info from s2
  5. union all
  6. select id,info from s3
  7. ) tmp where tmp.id<10\G
  8. *************************** 1. row ***************************
  9. EXPLAIN: -> Inner hash join (no condition) (cost=17274.36 rows=172368) (actual time=0.180..26.708 rows=180000 loops=1)
  10.     -> Table scan on s1 (cost=54.56 rows=9576) (actual time=0.010..8.718 rows=10000 loops=1)
  11.     -> Hash
  12.         -> Table scan on tmp (cost=10.57..13.15 rows=18) (actual time=0.148..0.150 rows=18 loops=1)
  13.             -> Union all materialize (cost=10.42..10.42 rows=18) (actual time=0.146..0.146 rows=18 loops=1)
  14.                 -> 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)
  15.                 -> 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)

  16. 1 row in set (0.10 sec)



上一篇:oracle非相关子查询处理方式
下一篇:mysql执行计划里索引访问算子和oracle的不同之处