ITPub博客

首页 > 数据库 > 数据库开发技术 > 深入SQL执行计划之CBO查询转换(6):子查询关联集展开机能(unnest correlation set subquery)

深入SQL执行计划之CBO查询转换(6):子查询关联集展开机能(unnest correlation set subquery)

原创 数据库开发技术 作者:lukeunique 时间:2021-04-15 08:27:42 0 删除 编辑

编者按:

本文作者系杨昱明,现就职于甲骨文公司,从事数据库方面的技术支持。希望能通过发表文章,把一些零散的知识再整理整理。个人主页:https://blog.csdn.net/weixin_50513167,经其本人授权发布。

【免责声明】本公众号文章仅代表个人观点,与任何公司无关。

本来关于 CBO 的 SQL 自动转换的介绍计划在上一次就想收口了,但突然间又想到了几个机能,看来还是要继续弄吧。


子查询关联集展开机能(unnest correlation set subquery)


这个机能,我在 Google 上查了一下,分享的文章特别少,可能是很少被关注到吧。

话不多说,还是马上上例子,在没用到子查询关联集展开机能之前,下面的 Case 会是什么样子。


drop table t1 purge;drop table t2 purge;drop table drv purge;

create table t1(key, pad) asselect to_char(rownum*2-1), lpad(' ',50) from dual connect by level <= 100;

create table t2(key, pad) asselect to_char(rownum*2), lpad(' ',50) from dual connect by level <= 100;

create table drv(key, pad) asselect rownum, lpad(' ',500) from dual connect by level <= 5union allselect -rownum, lpad(' ',500) from dual connect by level <= 1000;

exec dbms_stats.gather_table_stats(user, 'T1');exec dbms_stats.gather_table_stats(user, 'T2');exec dbms_stats.gather_table_stats(user, 'DRV');
SQL> alter session set "_optimizer_unnest_corr_set_subq" = FALSE;SQL> select key from drvwhere exists (    select null    from t1    where drv.key = to_number(t1.key)    union all    select null    from t2    where drv.key = to_number(t2.key)  );   2    3    4    5    6    7    8    9   10

KEY---------- 1 2 3 4         5
Execution Plan----------------------------------------------------------Plan hash value: 1881039188

----------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |----------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 5 | 3043 (1)| 00:00:01 ||* 1 | FILTER | | | | | || 2 | TABLE ACCESS FULL | DRV | 1005 | 5025 | 23 (0)| 00:00:01 || 3 | UNION-ALL | | | | | ||* 4 | TABLE ACCESS FULL| T1 | 1 | 4 | 3 (0)| 00:00:01 ||* 5 | TABLE ACCESS FULL| T2 | 1 | 4 | 3 (0)| 00:00:01 |----------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

1 - filter( EXISTS ( (SELECT NULL FROM "T1" "T1" WHERE TO_NUMBER("T1"."KEY")=:B1) UNION ALL (SELECT NULL FROM "T2" "T2"WHERE

TO_NUMBER("T2"."KEY")=:B2))) 4 - filter(TO_NUMBER("T1"."KEY")=:B1) 5 - filter(TO_NUMBER("T2"."KEY")=:B1)


t1 是奇数表,t2 偶数表,drv 是1到5的正数和-1到-1000的负数。

没用到子查询关联集展开机能之前,执行计划和【子查询展开机能(Subquery Unnesting)】一节中讲到的没用子查询展开是的效果一样。即,用子查询的 filter 的结果来对主查询进行 filter,只不过这次,子查询中 t1,t2 表作了 UNION ALL。


这个 Case 有个特点是,drv 同 t1 和 t2 用了相同字段来做结合。

这种情况下,如何展开子查询来做结合处理呢,这就用到了子查询关联集展开机能。


SQL> alter session set "_optimizer_unnest_corr_set_subq" = TRUE;SQL> select key from drvwhere exists (    select null    from t1    where drv.key = to_number(t1.key)    union all    select null    from t2    where drv.key = to_number(t2.key)  );  2    3    4    5    6    7    8    9   10

KEY---------- 1 2 3 4 5

Execution Plan----------------------------------------------------------Plan hash value: 1657361037

--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 18 | 29 (0)| 00:00:01 ||* 1 | HASH JOIN RIGHT SEMI| | 1 | 18 | 29 (0)| 00:00:01 || 2 | VIEW | VW_SQ_1 | 200 | 2600 | 6 (0)| 00:00:01 || 3 | UNION-ALL | | | | | || 4 | TABLE ACCESS FULL| T1 | 100 | 400 | 3 (0)| 00:00:01 || 5 | TABLE ACCESS FULL| T2 | 100 | 400 | 3 (0)| 00:00:01 || 6 | TABLE ACCESS FULL | DRV | 1005 | 5025 | 23 (0)| 00:00:01 |--------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

1 - access("DRV"."KEY"="VW_COL_1")


CBO 变换后的执行计划可以看出,t1,t2 表的 UNION ALL 的结果做成 View 之后和 drv 做 SEMI 结合。


那么到底是不是 CBO 内部自动转化了用户的 SQL 呢。还是看看 CBO 的 Trace 吧。


Final query after transformations:******* UNPARSED QUERY IS *******SELECT "DRV"."KEY" "KEY" FROM  ( (SELECT TO_NUMBER("T1"."KEY") "ITEM_2" FROM "U1"."T1" "T1") UNION ALL  (SELECT TO_NUMBER("T2"."KEY") "ITEM_1" FROM "U1"."T2" "T2")) "VW_SQ_1","U1"."DRV" "DRV" WHERE "DRV"."KEY"="VW_SQ_1"."VW_COL_1"


没错,确实是自动转换了,t1 和 t2 做 UNION ALL 后以 View 的形式同 drv 结合。


上面的例子也可以看出来,这个机能是用隐藏参数 “_optimizer_unnest_corr_set_subq” 来控制的。


后续文章更加精彩,欢迎关注本公众号或访问【阅读原文】。

——End——


专注于技术不限于技术!

用碎片化的时间,一点一滴地提高数据库技术和个人能力。

欢迎关注!

手把手系列(帮助个人技术成长):

SQL调优和诊断从哪入手?

获取SQL执行计划最基础的方法是啥?

一学就会的获取SQL执行计划和性能统计信息的方法

在线Oracle SQL学习环境--Live SQL

Oracle优化器架构变化和特定行为

获取历史执行计划:AWR/StatsPack SQL 报告

Oracle SQL 性能调优:使用SqlPatch固定执行计划

供收藏:Oracle固定SQL执行计划的方法总结

Oracle SQL 性能调优:使用Hint固定执行计划1(Hash Join)

Oracle SQL 性能调优:使用SqlPatch固定执行计划

Oracle SQL 性能调优:使用SqlPatch固定执行计划(二)19c


CBO 查询转换系列(了解Oracle优化器)

CBO 查询转换(1):子查询展开机能(Subquery Unnesting)

CBO 查询转换(2):反结合的NULL识别机能(null aware anti-join )

CBO 查询转换(3):结合谓词下推机能(Join Predicate Pushdown)

CBO 查询转换 (4):Group By 配置最优机能(Group By Placement)

CBO查询转换(5):星型转换(Star Transformation)

原文作者:SQL和数据库技术;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2017-07-21

  • 博文量
    107
  • 访问量
    63595