性能调优:JPPD(连接谓词推入)在不同版本之间的差别

[复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
我们的文章会在微信公众号Oracle规复实录和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面欣赏效果更佳。
在日常的数据库运维和开发工作中,性能调优一直是让人头疼又不得不面临的话题。尤其是在处置惩罚JPPD(Join Predicate Push-Down)相关的性能题目时,很多同学会碰到“明明加了索引,SQL还是慢”、“连接条件推不下去”等让人狐疑的征象。其实,这背后不仅仅是SQL写法的题目,更涉及到数据库优化器的工作原理和一些容易被忽视的细节。
本文将通过一个使用多个版本在JPPD中不同的行为,带你一步步分析JPPD连接谓词推入失败的BUG定位方法,并结合实际案例,资助你快速定位和解决雷同的性能瓶颈。无论你是数据库新手,还是有经验的DBA,相信都能从中获得实用的调优思路和本领。
本案例也是来自于朋侪案例的分享,同事咨询我的一个sql案例,数据库版本为11.2.0.4,经过同事的分析发现,sql性能差的原因是没有做连接谓词推入,但是没有找到原因,具体的SQL语句如下:
  1. WITH   TEMP AS
  2. (SELECT /*+ INLINE  */
  3.    DO.PROVORGCODE,
  4.    DO.PROVORGNAME,
  5.    DO.CITYORGCODE,
  6.    DO.CITYORGNAME,
  7.    DO.TOWNORGCODE,
  8.    DO.TOWNORGNAME,
  9.    D.TEAM_ID_AREA,
  10.    D.TEAM_NAME_AREA,
  11.    D.TEAM_ID_DEPT,
  12.    D.TEAM_NAME_DEPT,
  13.    D.TEAM_ID_GRP,
  14.    D.TEAM_NAME_GRP,
  15.    T02.CHANNEL_ID,
  16.    T02.SALES_NAME,
  17.    T02.SALES_CODE,
  18.    T02.PROBATION_DATE,
  19.    T02.RANK,
  20.    T02.ENTER_RANK
  21.     FROM ODSUSER.T02SALESINFO_BACKUP T02
  22.    INNER JOIN DMUSER.D_AGENT DA
  23.       ON T02.SALES_CODE = DA.AGENTCODE
  24.    INNER JOIN DMUSER.D_ORG DO
  25.       ON T02.BRANCH_ID = DO.ORGCODE
  26.    INNER JOIN DMUSER.D_TEAMINFO_CHANNEL D
  27.       ON T02.TEAM_ID = D.TEAM_ID
  28.      AND T02.CHANNEL_ID = D.CHANNEL_ID
  29.    WHERE T02.YEAR_MONTH =
  30.          TO_CHAR(to_date('2023-11-30', 'yyyy-mm-dd'), 'YYYYMM')
  31.      AND DA.ENTERCOMPDATE <= to_date('2023-11-30', 'yyyy-mm-dd')
  32.      AND (DA.LEAVECOMPDATE > to_date('2023-11-30', 'yyyy-mm-dd') OR
  33.          DA.LEAVECOMPDATE IS NULL)
  34.      and D.TEAM_ID_GRP = '1411005026'
  35.      AND T02.CHANNEL_ID IN ('05')),
  36. A AS
  37. (SELECT *
  38.     FROM TEMP
  39.     LEFT JOIN (SELECT /*+ PUSH_PRED */
  40.                T.AGENTCODE,
  41.                SUM(T.ZX_CUST_CNT) ZX_CUST_CNT,
  42.                LEAST(SUM(NVL(T.ZT_PLCY_CNT_L, 0)), 5) + SUM(T.ZT_PLCY_CNT) ZT_PLCY_CNT,
  43.                SUM(T.SX_PLCY_CNT) SX_PLCY_CNT,
  44.                SUM(T.SHARE_COUNT) SHARE_COUNT,
  45.                0 HD_CUST_CNT,
  46.                0 HY_CUST_CNT,
  47.                0 BD_CUST_CNT,
  48.                SUM(TARGET_PREM_NUM) TARGET_PREM_NUM,
  49.                SUM(OFFLINE_NUM) OFFLINE_NUM,
  50.                SUM(VALIDATE_CUST_NUM) VALIDATE_CUST_NUM,
  51.                SUM(FSNN_SX_CNT) FSNN_SX_CNT,
  52.                SUM(T.JCX_CNT) JCX_CNT,
  53.                0 ZF_CNT,
  54.                SUM(NVL(T.SX_PLCY_CNT_L, 0)) SX_PLCY_CNT_L,
  55.                SUM(NVL(T.JCX_CNT_L, 0)) JCX_CNT_L,
  56.                0 ZF_CNT_L
  57.                 FROM DMA_XSHDL_BFZ_RPT T
  58.                WHERE T.DATEID >= TO_DATE('2023-11-01', 'YYYY-MM-DD')
  59.                  AND T.DATEID <= TO_DATE('2023-11-30', 'YYYY-MM-DD')
  60.                GROUP BY T.AGENTCODE
  61.               UNION ALL
  62.               SELECT /*+ PUSH_PRED */T.AGENT_CODE,
  63.                      0 ZX_CUST_CNT,
  64.                      0 ZT_PLCY_CNT,
  65.                      0 SX_PLCY_CNT,
  66.                      0 SHARE_COUNT,
  67.                      0 HD_CUST_CNT,
  68.                      0 HY_CUST_CNT,
  69.                      0 BD_CUST_CNT,
  70.                      0 TARGET_PREM_NUM,
  71.                      COUNT(1) OFFLINE_NUM,
  72.                      0 VALIDATE_CUST_NUM,
  73.                      0 FSNN_SX_CNT,
  74.                      0 JCX_CNT,
  75.                      0 ZF_CNT,
  76.                      0 SX_PLCY_CNT_L,
  77.                      0 JCX_CNT_L,
  78.                      0 ZF_CNT_L
  79.                 FROM (SELECT DISTINCT T.AGENT_CODE,
  80.                                       T.CUST_NAME,
  81.                                       T.GENDER,
  82.                                       T.CONTACT_PHONE_NUM
  83.                         FROM intf_rpt_user.DMA_MKT_MARKET_CUST_MEMBER T
  84.                        WHERE T.SIGN_TIME >=
  85.                              to_date('2023-11-01', 'yyyy-mm-dd')
  86.                          AND T.SIGN_TIME <
  87.                              to_date('2023-11-30', 'yyyy-mm-dd') + 1) T
  88.                GROUP BY T.AGENT_CODE) T
  89.       ON TEMP.SALES_CODE = T.AGENTCODE)
  90.           select  /*+ 11 */* from A
复制代码
看看实行操持:
  1. ============
  2. Plan Table
  3. ============
  4. -----------------------------------------------------------------------+-----------------------------------+
  5. | Id  | Operation                          | Name                      | Rows  | Bytes | Cost  | Time      |
  6. -----------------------------------------------------------------------+-----------------------------------+
  7. | 0   | SELECT STATEMENT                   |                           |       |       |  108K |           |
  8. | 1   |  NESTED LOOPS                      |                           |    12 |  6372 |  108K |  00:22:13 |
  9. | 2   |   NESTED LOOPS                     |                           |    12 |  6372 |  108K |  00:22:13 |
  10. | 3   |    HASH JOIN OUTER                 |                           |    12 |  6048 |  108K |  00:22:12 |
  11. | 4   |     NESTED LOOPS                   |                           |    12 |  3996 |   542 |  00:00:07 |
  12. | 5   |      NESTED LOOPS                  |                           |    12 |  3996 |   542 |  00:00:07 |
  13. | 6   |       NESTED LOOPS                 |                           |    12 |  2736 |   518 |  00:00:07 |
  14. | 7   |        TABLE ACCESS BY INDEX ROWID | D_TEAMINFO_CHANNEL        |     1 |   147 |     5 |  00:00:01 |
  15. | 8   |         INDEX RANGE SCAN           | IDX_TEAMINFO_TEAMGRP      |     1 |       |     3 |  00:00:01 |
  16. | 9   |        TABLE ACCESS BY INDEX ROWID | T02SALESINFO_BACKUP       |    86 |  6966 |   513 |  00:00:07 |
  17. | 10  |         INDEX RANGE SCAN           | IDX_T02SALESBACK_TEAM_CHA |   608 |       |     4 |  00:00:01 |
  18. | 11  |       INDEX RANGE SCAN             | IDX_ORGCODE               |     1 |       |     1 |  00:00:01 |
  19. | 12  |      TABLE ACCESS BY INDEX ROWID   | D_ORG                     |     1 |   105 |     2 |  00:00:01 |
  20. | 13  |     VIEW                           |                           |   95K |   16M |  108K |  00:22:06 |
  21. | 14  |      UNION-ALL                     |                           |       |       |       |           |
  22. | 15  |       HASH GROUP BY                |                           |   13K |  757K |   91K |  00:19:42 |
  23. | 16  |        TABLE ACCESS STORAGE FULL   | DMA_XSHDL_BFZ_RPT         |   14K |  797K |   91K |  00:19:42 |
  24. | 17  |       HASH GROUP BY                |                           |   81K | 1466K |   17K |  00:03:24 |
  25. | 18  |        VIEW                        |                           |   81K | 1466K |   17K |  00:03:24 |
  26. | 19  |         HASH UNIQUE                |                           |   81K | 4804K |   17K |  00:03:24 |
  27. | 20  |          TABLE ACCESS STORAGE FULL | DMA_MKT_MARKET_CUST_MEMBER|   81K | 4804K |   15K |  00:03:11 |
  28. | 21  |    INDEX RANGE SCAN                | IDX_AGENT_AGENTCODE       |     1 |       |     2 |  00:00:01 |
  29. | 22  |   TABLE ACCESS BY INDEX ROWID      | D_AGENT                   |     1 |    27 |     3 |  00:00:01 |
  30. -----------------------------------------------------------------------+-----------------------------------+
  31. Predicate Information:
  32. ----------------------
  33. 3 - access("T02"."SALES_CODE"="T"."AGENTCODE")
  34. 7 - filter("D"."CHANNEL_ID"='05')
  35. 8 - access("D"."TEAM_ID_GRP"='1411005026')
  36. 9 - filter("T02"."YEAR_MONTH"='202311')
  37. 10 - access("T02"."TEAM_ID"="D"."TEAM_ID" AND "T02"."CHANNEL_ID"='05')
  38. 11 - access("T02"."BRANCH_ID"="DO"."ORGCODE")
  39. 16 - access(("T"."DATEID">=TO_DATE(' 2023-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "T"."DATEID"<=TO_DATE(' 2023-11-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
  40. 16 - filter(("T"."DATEID">=TO_DATE(' 2023-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "T"."DATEID"<=TO_DATE(' 2023-11-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
  41. 20 - access(("T"."SIGN_TIME">=TO_DATE(' 2023-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "T"."SIGN_TIME"<TO_DATE(' 2023-12-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
  42. 20 - filter(("T"."SIGN_TIME">=TO_DATE(' 2023-11-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "T"."SIGN_TIME"<TO_DATE(' 2023-12-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
  43. 21 - access("T02"."SALES_CODE"="DA"."AGENTCODE")
  44. 22 - filter((("DA"."LEAVECOMPDATE" IS NULL OR "DA"."LEAVECOMPDATE">TO_DATE(' 2023-11-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) AND "DA"."ENTERCOMPDATE"<=TO_DATE(' 2023-11-30 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
  45. Content of other_xml column
  46. ===========================
  47.   db_version     : 11.2.0.4
  48.   parse_schema   : INTF_RPT_USER
  49.   dynamic_sampling: 2
  50.   plan_hash      : 2407633558
  51.   plan_hash_2    : 3749594226
  52.   Outline Data:
  53.   /*+
  54.     BEGIN_OUTLINE_DATA
  55.       IGNORE_OPTIM_EMBEDDED_HINTS
  56.       OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
  57.       DB_VERSION('11.2.0.4')
  58.       ALL_ROWS
  59.       OUTLINE_LEAF(@"SEL$2")
  60.       OUTLINE_LEAF(@"SEL$4")
  61.       OUTLINE_LEAF(@"SEL$3")
  62.       OUTLINE_LEAF(@"SET$1")
  63.       OUTLINE_LEAF(@"SEL$79A905B1")
  64.       MERGE(@"SEL$1A4CF335")
  65.       OUTLINE(@"SEL$11")
  66.       OUTLINE(@"SEL$1A4CF335")
  67.       MERGE(@"SEL$CEFD41C7")
  68.       OUTLINE(@"SEL$10")
  69.       OUTLINE(@"SEL$CEFD41C7")
  70.       MERGE(@"SEL$1")
  71.       MERGE(@"SEL$AB668856")
  72.       OUTLINE(@"SEL$5")
  73.       OUTLINE(@"SEL$1")
  74.       OUTLINE(@"SEL$AB668856")
  75.       MERGE(@"SEL$E16E17DA")
  76.       OUTLINE(@"SEL$9")
  77.       OUTLINE(@"SEL$E16E17DA")
  78.       MERGE(@"SEL$6DE49B00")
  79.       OUTLINE(@"SEL$8")
  80.       OUTLINE(@"SEL$6DE49B00")
  81.       MERGE(@"SEL$6")
  82.       OUTLINE(@"SEL$7")
  83.       OUTLINE(@"SEL$6")
  84.       INDEX_RS_ASC(@"SEL$79A905B1" "D"@"SEL$8" ("D_TEAMINFO_CHANNEL"."TEAM_ID_GRP"))
  85.       INDEX_RS_ASC(@"SEL$79A905B1" "T02"@"SEL$6" ("T02SALESINFO_BACKUP"."TEAM_ID" "T02SALESINFO_BACKUP"."CHANNEL_ID"))
  86.       INDEX(@"SEL$79A905B1" "DO"@"SEL$7" ("D_ORG"."ORGCODE"))
  87.       NO_ACCESS(@"SEL$79A905B1" "T"@"SEL$1")
  88.       INDEX(@"SEL$79A905B1" "DA"@"SEL$6" ("D_AGENT"."AGENTCODE"))
  89.       LEADING(@"SEL$79A905B1" "D"@"SEL$8" "T02"@"SEL$6" "DO"@"SEL$7" "T"@"SEL$1" "DA"@"SEL$6")
  90.       USE_NL(@"SEL$79A905B1" "T02"@"SEL$6")
  91.       USE_NL(@"SEL$79A905B1" "DO"@"SEL$7")
  92.       NLJ_BATCHING(@"SEL$79A905B1" "DO"@"SEL$7")
  93.       USE_HASH(@"SEL$79A905B1" "T"@"SEL$1")
  94.       USE_NL(@"SEL$79A905B1" "DA"@"SEL$6")
  95.       NLJ_BATCHING(@"SEL$79A905B1" "DA"@"SEL$6")
  96.       NO_ACCESS(@"SEL$3" "T"@"SEL$3")
  97.       USE_HASH_AGGREGATION(@"SEL$3")
  98.       FULL(@"SEL$2" "T"@"SEL$2")
  99.       USE_HASH_AGGREGATION(@"SEL$2")
  100.       FULL(@"SEL$4" "T"@"SEL$4")
  101.       USE_HASH_AGGREGATION(@"SEL$4")
  102.     END_OUTLINE_DATA
  103.   */
复制代码
这很有可能是bug了,由于正好我的版本比较高19c,可以通过遍历fix control去排查,这里其实还有一个本领,就是假如明确了是哪个功能出现了bug的话,可以直接去fix control里面查询看看11g之后修复了哪个bug从而修复了这个题目。
  1. JPPD:     JPPD bypassed: View is a set query block.
复制代码
很显着命中了bug 21099502,描述为Enable extended JPPD for UNION[ALL] views having group by,在12.2修复的。
查询MOS,Bug 21099502 Join Predicates not pushed into UNION ALL view having group by and aggregates,非常匹配。该bug在12.2修复。
  1. 19c:
  2. SQL> explain plan for
  3. select t1.object_id,t1.object_name from test.t1,
  4.   2    3  (select object_id,count(*)
  5.   4    from test.t
  6. group by object_id
  7.   5    6  union all
  8.   7  select object_id,count(*)
  9.   8    from test.t
  10.   9   group by object_id) t
  11. 10  where t1.owner='SYS' and t.object_id(+)=t1.object_id;
  12. Explained.
  13. SQL> select * from table(dbms_xplan.display);
  14. PLAN_TABLE_OUTPUT
  15. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  16. Plan hash value: 4122290605
  17. ------------------------------------------------------------------------------------------------
  18. | Id  | Operation                     | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
  19. ------------------------------------------------------------------------------------------------
  20. |   0 | SELECT STATEMENT              |                |  5843 |   285K| 17927   (1)| 00:00:01 |
  21. |   1 |  NESTED LOOPS OUTER           |                |  5843 |   285K| 17927   (1)| 00:00:01 |
  22. |*  2 |   TABLE ACCESS FULL           | T1             |  2921 |   128K|   396   (1)| 00:00:01 |
  23. |   3 |   VIEW                        |                |     1 |     5 |     6   (0)| 00:00:01 |
  24. |   4 |    UNION ALL PUSHED PREDICATE |                |       |       |            |          |
  25. |   5 |     SORT GROUP BY             |                |     1 |     5 |     3   (0)| 00:00:01 |
  26. |*  6 |      INDEX RANGE SCAN         | IDX_T_OBJECTID |    32 |   160 |     3   (0)| 00:00:01 |
  27. |   7 |     SORT GROUP BY             |                |     1 |     5 |     3   (0)| 00:00:01 |
  28. |*  8 |      INDEX RANGE SCAN         | IDX_T_OBJECTID |    32 |   160 |     3   (0)| 00:00:01 |
  29. ------------------------------------------------------------------------------------------------
  30. Predicate Information (identified by operation id):
  31. ---------------------------------------------------
  32.    2 - filter("T1"."OWNER"='SYS')
  33.    6 - access("OBJECT_ID"="T1"."OBJECT_ID")
  34.    8 - access("OBJECT_ID"="T1"."OBJECT_ID")
  35. 11g:
  36. SQL> alter session set optimizer_features_enable='11.2.0.4';
  37. Session altered.
  38. SQL> explain plan for
  39.   2  select t1.object_id,t1.object_name from test.t1,
  40.   3  (select object_id,count(*)
  41.   4    from test.t
  42.   5   group by object_id
  43.   6  union all
  44.   7  select object_id,count(*)
  45.   8    from test.t
  46.   9   group by object_id) t
  47. 10  where t1.owner='SYS' and t.object_id(+)=t1.object_id;
  48. Explained.
  49. SQL> select * from table(dbms_xplan.display);
  50. PLAN_TABLE_OUTPUT
  51. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  52. Plan hash value: 1399071787
  53. --------------------------------------------------------------------------------------
  54. | Id  | Operation             | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
  55. --------------------------------------------------------------------------------------
  56. |   0 | SELECT STATEMENT      |      |  5843 |   330K|       | 30692   (1)| 00:00:02 |
  57. |*  1 |  HASH JOIN OUTER      |      |  5843 |   330K|       | 30692   (1)| 00:00:02 |
  58. |*  2 |   TABLE ACCESS FULL   | T1   |  2921 |   128K|       |   396   (1)| 00:00:01 |
  59. |   3 |   VIEW                |      |   148K|  1880K|       | 30296   (1)| 00:00:02 |
  60. |   4 |    UNION-ALL          |      |       |       |       |            |          |
  61. |   5 |     HASH GROUP BY     |      | 74064 |   361K|    26M| 15148   (1)| 00:00:01 |
  62. PLAN_TABLE_OUTPUT
  63. --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  64. |   6 |      TABLE ACCESS FULL| T    |  2337K|    11M|       | 12442   (1)| 00:00:01 |
  65. |   7 |     HASH GROUP BY     |      | 74064 |   361K|    26M| 15148   (1)| 00:00:01 |
  66. |   8 |      TABLE ACCESS FULL| T    |  2337K|    11M|       | 12442   (1)| 00:00:01 |
  67. --------------------------------------------------------------------------------------
  68. Predicate Information (identified by operation id):
  69. ---------------------------------------------------
  70.    1 - access("T"."OBJECT_ID"(+)="T1"."OBJECT_ID")
  71.    2 - filter("T1"."OWNER"='SYS')
复制代码
应该是CBO在JPPD查询转换时,在12.2版本之前漏掉了UNION ALL内嵌视图中包含group by的情况,在12.2版本做了修复。
------------------作者介绍-----------------------
姓名:黄廷忠
现就职:Oracle中国高级服务团队
曾就职:OceanBase、云和恩墨、东方龙马等
电话、微信、QQ:18081072613


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5

GMT+8, 2025-6-19 21:05 , Processed in 0.103281 second(s), 32 queries 手机版|qidao123.com技术社区-IT企服评测▪应用市场 ( 浙ICP备20004199 )|网站地图

快速回复 返回顶部 返回列表