_optimizer_null_aware_antijoin引发的SQL性能问题

本站文章除注明转载外,均为本站原创: 转载自love wife & love life —Roger 的Oracle技术博客

本文链接地址: _optimizer_null_aware_antijoin引发的SQL性能问题

前几天某客户联系我说之前我们进行存储迁移的系统,有个SQL跑的极慢,根本跑不出来结果。通过VPN登录看了下,SQL确认跑的很慢。开始我很难理解,我们仅仅是进行了存储迁移,数据库基本上没动,为什么会有SQL性能问题呢?  我们先来看看有问题的SQL:

SYS@rptdb1> set autot traceonly exp
SYS@rptdb1> select a.*,b.rate TAX_RATE,round(a.charge*b.rate/(1+b.rate),0) tax,a.charge-round((a.charge*b.rate/(1+b.rate)),0) charge_flh,1 flag,b.tax_rule_id
  2               from statrpt.rpt_offer_rate b,statrpt.tmp_item_aggr_ex_691  a
  3               where  a.acct_item_type_id = b.acct_item_type_id
  4               and a.offer_cd =b.offer_ID
  5             union all
  6
SYS@rptdb1>              select a.*,b.rate TAX_RATE,round(a.charge*b.rate/(1+b.rate),0) tax,a.charge-ROUND((a.charge*b.rate/(1+b.rate)),0) charge_flh,2,b.tax_rule_id
  2               from  statrpt.rpt_product_rate b,statrpt.tmp_item_aggr_ex_691  a
  3               where   a.acct_item_type_id = b.acct_item_type_id
  4               and  a.product_id=b.product_id
  5               and (a.acct_item_type_id,a.offer_cd) not in(select acct_item_type_id,offer_id from statrpt.rpt_offer_rate)
  6              union all
  7
SYS@rptdb1>              select a.*,b.rate TAX_RATE,round(a.charge*b.rate/(1+b.rate),0) tax,a.charge-round((a.charge*b.rate/(1+b.rate)),0) charge_flh,3,b.tax_rule_id
  2               from  statrpt.rpt_zm_rate b,statrpt.tmp_item_aggr_ex_691  a
  3               where  a.acct_item_type_id = b.acct_item_type_id
  4               and (a.acct_item_type_id,a.offer_cd)not in(select acct_item_type_id,offer_id from statrpt.rpt_offer_rate )
  5               and (a.acct_item_type_id,a.product_id) not in(select acct_item_type_id,product_id from statrpt.rpt_product_rate )
  6               union all
  7               select a.*,b.rate TAX_RATE,round(a.charge*b.rate/(1+b.rate),0) tax,a.charge-round((a.charge*b.rate/(1+b.rate)),0) charge_flh,4,b.tax_rule_id
  8               from  statrpt.tmp_zm_only_rate b,statrpt.tmp_item_aggr_ex_691  a
  9               where  a.acct_item_type_id = b.acct_item_type_id
 10               and (a.acct_item_type_id,a.offer_cd)not in(select acct_item_type_id,offer_id from statrpt.rpt_offer_rate )
 11               and (a.acct_item_type_id,a.product_id) not in(select acct_item_type_id,product_id from statrpt.rpt_product_rate )
 12               and (a.acct_item_type_id) not in(select acct_item_type_id from statrpt.rpt_zm_rate )
 13  /
Elapsed: 00:00:00.00

Execution Plan
----------------------------------------------------------
Plan hash value: 1624413711

-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |                      |  6983K|   765M|   563M (51)|999:59:59 |        |      |            |
|   1 |  UNION-ALL                |                      |       |       |            |          |        |      |            |
|*  2 |   FILTER                  |                      |       |       |            |          |        |      |            |
|   3 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|   4 |     PX SEND QC (RANDOM)   | :TQ60001             |  3494K|   383M|  1050   (1)| 00:00:13 |  Q6,01 | P->S | QC (RAND)  |
|*  5 |      HASH JOIN            |                      |  3494K|   383M|  1050   (1)| 00:00:13 |  Q6,01 | PCWP |            |
|   6 |       PX RECEIVE          |                      |  1034 | 14476 |     3   (0)| 00:00:01 |  Q6,01 | PCWP |            |
|   7 |        PX SEND BROADCAST  | :TQ60000             |  1034 | 14476 |     3   (0)| 00:00:01 |  Q6,00 | P->P | BROADCAST  |
|   8 |         PX BLOCK ITERATOR |                      |  1034 | 14476 |     3   (0)| 00:00:01 |  Q6,00 | PCWC |            |
|   9 |          TABLE ACCESS FULL| RPT_ZM_RATE          |  1034 | 14476 |     3   (0)| 00:00:01 |  Q6,00 | PCWP |            |
|  10 |       PX BLOCK ITERATOR   |                      |  3494K|   336M|  1046   (1)| 00:00:13 |  Q6,01 | PCWC |            |
|  11 |        TABLE ACCESS FULL  | TMP_ITEM_AGGR_EX_691 |  3494K|   336M|  1046   (1)| 00:00:13 |  Q6,01 | PCWP |            |
|  12 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|  13 |     PX SEND QC (RANDOM)   | :TQ10000             |     1 |     9 |     8   (0)| 00:00:01 |  Q1,00 | P->S | QC (RAND)  |
|  14 |      PX BLOCK ITERATOR    |                      |     1 |     9 |     8   (0)| 00:00:01 |  Q1,00 | PCWC |            |
|* 15 |       TABLE ACCESS FULL   | RPT_OFFER_RATE       |     1 |     9 |     8   (0)| 00:00:01 |  Q1,00 | PCWP |            |
|  16 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|  17 |     PX SEND QC (RANDOM)   | :TQ20000             |     1 |     9 |    96   (2)| 00:00:02 |  Q2,00 | P->S | QC (RAND)  |
|  18 |      PX BLOCK ITERATOR    |                      |     1 |     9 |    96   (2)| 00:00:02 |  Q2,00 | PCWC |            |
|* 19 |       TABLE ACCESS FULL   | RPT_PRODUCT_RATE     |     1 |     9 |    96   (2)| 00:00:02 |  Q2,00 | PCWP |            |
|* 20 |   FILTER                  |                      |       |       |            |          |        |      |            |
|  21 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|  22 |     PX SEND QC (RANDOM)   | :TQ70001             |  3494K|   383M|  1050   (1)| 00:00:13 |  Q7,01 | P->S | QC (RAND)  |
|* 23 |      HASH JOIN            |                      |  3494K|   383M|  1050   (1)| 00:00:13 |  Q7,01 | PCWP |            |
|  24 |       PX RECEIVE          |                      |  6053 | 84742 |     3   (0)| 00:00:01 |  Q7,01 | PCWP |            |
|  25 |        PX SEND BROADCAST  | :TQ70000             |  6053 | 84742 |     3   (0)| 00:00:01 |  Q7,00 | P->P | BROADCAST  |
|  26 |         PX BLOCK ITERATOR |                      |  6053 | 84742 |     3   (0)| 00:00:01 |  Q7,00 | PCWC |            |
|  27 |          TABLE ACCESS FULL| TMP_ZM_ONLY_RATE     |  6053 | 84742 |     3   (0)| 00:00:01 |  Q7,00 | PCWP |            |
|  28 |       PX BLOCK ITERATOR   |                      |  3494K|   336M|  1046   (1)| 00:00:13 |  Q7,01 | PCWC |            |
|  29 |        TABLE ACCESS FULL  | TMP_ITEM_AGGR_EX_691 |  3494K|   336M|  1046   (1)| 00:00:13 |  Q7,01 | PCWP |            |
|  30 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|  31 |     PX SEND QC (RANDOM)   | :TQ30000             |     1 |     9 |     8   (0)| 00:00:01 |  Q3,00 | P->S | QC (RAND)  |
|  32 |      PX BLOCK ITERATOR    |                      |     1 |     9 |     8   (0)| 00:00:01 |  Q3,00 | PCWC |            |
|* 33 |       TABLE ACCESS FULL   | RPT_OFFER_RATE       |     1 |     9 |     8   (0)| 00:00:01 |  Q3,00 | PCWP |            |
|  34 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|  35 |     PX SEND QC (RANDOM)   | :TQ40000             |     1 |     9 |    96   (2)| 00:00:02 |  Q4,00 | P->S | QC (RAND)  |
|  36 |      PX BLOCK ITERATOR    |                      |     1 |     9 |    96   (2)| 00:00:02 |  Q4,00 | PCWC |            |
|* 37 |       TABLE ACCESS FULL   | RPT_PRODUCT_RATE     |     1 |     9 |    96   (2)| 00:00:02 |  Q4,00 | PCWP |            |
|  38 |    PX COORDINATOR         |                      |       |       |            |          |        |      |            |
|  39 |     PX SEND QC (RANDOM)   | :TQ50000             |     1 |     5 |     3   (0)| 00:00:01 |  Q5,00 | P->S | QC (RAND)  |
|  40 |      PX BLOCK ITERATOR    |                      |     1 |     5 |     3   (0)| 00:00:01 |  Q5,00 | PCWC |            |
|* 41 |       TABLE ACCESS FULL   | RPT_ZM_RATE          |     1 |     5 |     3   (0)| 00:00:01 |  Q5,00 | PCWP |            |
-------------------------------------------------------------------------------------------------------------------------------

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

   2 - filter( NOT EXISTS (SELECT 0 FROM "STATRPT"."RPT_OFFER_RATE" "RPT_OFFER_RATE" WHERE
              LNNVL("ACCT_ITEM_TYPE_ID"<>:B1) AND LNNVL("OFFER_ID"<>:B2)) AND  NOT EXISTS (SELECT 0 FROM
              "STATRPT"."RPT_PRODUCT_RATE" "RPT_PRODUCT_RATE" WHERE LNNVL("ACCT_ITEM_TYPE_ID"<>:B3) AND LNNVL("PRODUCT_ID"<>:B4)))
   5 - access("A"."ACCT_ITEM_TYPE_ID"="B"."ACCT_ITEM_TYPE_ID")
  15 - filter(LNNVL("ACCT_ITEM_TYPE_ID"<>:B1) AND LNNVL("OFFER_ID"<>:B2))
  19 - filter(LNNVL("ACCT_ITEM_TYPE_ID"<>:B1) AND LNNVL("PRODUCT_ID"<>:B2))
  20 - filter( NOT EXISTS (SELECT 0 FROM "STATRPT"."RPT_OFFER_RATE" "RPT_OFFER_RATE" WHERE
              LNNVL("ACCT_ITEM_TYPE_ID"<>:B1) AND LNNVL("OFFER_ID"<>:B2)) AND  NOT EXISTS (SELECT 0 FROM
              "STATRPT"."RPT_PRODUCT_RATE" "RPT_PRODUCT_RATE" WHERE LNNVL("ACCT_ITEM_TYPE_ID"<>:B3) AND LNNVL("PRODUCT_ID"<>:B4))
              AND  NOT EXISTS (SELECT 0 FROM "STATRPT"."RPT_ZM_RATE" "RPT_ZM_RATE" WHERE LNNVL("ACCT_ITEM_TYPE_ID"<>:B5)))
  23 - access("A"."ACCT_ITEM_TYPE_ID"="B"."ACCT_ITEM_TYPE_ID")
  33 - filter(LNNVL("ACCT_ITEM_TYPE_ID"<>:B1) AND LNNVL("OFFER_ID"<>:B2))
  37 - filter(LNNVL("ACCT_ITEM_TYPE_ID"<>:B1) AND LNNVL("PRODUCT_ID"<>:B2))
  41 - filter(LNNVL("ACCT_ITEM_TYPE_ID"<>:B1))

 

 

大家看该SQL的执行计划就知道,COST巨大无比,很显然这个SQL基本上是跑不动的。本人SQL优化比较弱,因此直接从原库进行对比,因此在原库跑了下SQL:

Plan hash value: 2514835211

---------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name                 | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                      |       |       |       |  3493 (100)|          |        |      |            |
|   1 |  UNION-ALL                      |                      |       |       |       |            |          |        |      |            |
|   2 |   PX COORDINATOR                |                      |       |       |       |            |          |        |      |            |
|   3 |    PX SEND QC (RANDOM)          | :TQ10004             |   557 | 71853 |       |  1745   (3)| 00:00:21 |  Q1,04 | P->S | QC (RAND)  |
|*  4 |     HASH JOIN BUFFERED          |                      |   557 | 71853 |       |  1745   (3)| 00:00:21 |  Q1,04 | PCWP |            |
|   5 |      PX RECEIVE                 |                      |   557 | 64055 |       |  1742   (3)| 00:00:21 |  Q1,04 | PCWP |            |
|   6 |       PX SEND HASH              | :TQ10002             |   557 | 64055 |       |  1742   (3)| 00:00:21 |  Q1,02 | P->P | HASH       |
|   7 |        MERGE JOIN ANTI NA       |                      |   557 | 64055 |       |  1742   (3)| 00:00:21 |  Q1,02 | PCWP |            |
|   8 |         SORT JOIN               |                      | 55738 |  5769K|    12M|  1733   (3)| 00:00:21 |  Q1,02 | PCWP |            |
|   9 |          MERGE JOIN ANTI NA     |                      | 55738 |  5769K|       |  1732   (3)| 00:00:21 |  Q1,02 | PCWP |            |
|  10 |           SORT JOIN             |                      |  5573K|   515M|  1643M|  1631   (2)| 00:00:20 |  Q1,02 | PCWP |            |
|  11 |            PX BLOCK ITERATOR    |                      |  5573K|   515M|       |  1614   (1)| 00:00:20 |  Q1,02 | PCWC |            |
|* 12 |             TABLE ACCESS FULL   | TMP_ITEM_AGGR_EX_691 |  5573K|   515M|       |  1614   (1)| 00:00:20 |  Q1,02 | PCWP |            |
|* 13 |           SORT UNIQUE           |                      |   421K|  3704K|    16M|   101   (5)| 00:00:02 |  Q1,02 | PCWP |            |
|  14 |            PX RECEIVE           |                      |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q1,02 | PCWP |            |
|  15 |             PX SEND BROADCAST   | :TQ10000             |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q1,00 | P->P | BROADCAST  |
|  16 |              PX BLOCK ITERATOR  |                      |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q1,00 | PCWC |            |
|* 17 |               TABLE ACCESS FULL | RPT_PRODUCT_RATE     |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q1,00 | PCWP |            |
|* 18 |         SORT UNIQUE             |                      | 22695 |   199K|       |     9  (12)| 00:00:01 |  Q1,02 | PCWP |            |
|  19 |          PX RECEIVE             |                      | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q1,02 | PCWP |            |
|  20 |           PX SEND BROADCAST     | :TQ10001             | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q1,01 | P->P | BROADCAST  |
|  21 |            PX BLOCK ITERATOR    |                      | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q1,01 | PCWC |            |
|* 22 |             TABLE ACCESS FULL   | RPT_OFFER_RATE       | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q1,01 | PCWP |            |
|  23 |      PX RECEIVE                 |                      |  1059 | 14826 |       |     3   (0)| 00:00:01 |  Q1,04 | PCWP |            |
|  24 |       PX SEND HASH              | :TQ10003             |  1059 | 14826 |       |     3   (0)| 00:00:01 |  Q1,03 | P->P | HASH       |
|  25 |        PX BLOCK ITERATOR        |                      |  1059 | 14826 |       |     3   (0)| 00:00:01 |  Q1,03 | PCWC |            |
|* 26 |         TABLE ACCESS FULL       | RPT_ZM_RATE          |  1059 | 14826 |       |     3   (0)| 00:00:01 |  Q1,03 | PCWP |            |
|  27 |   PX COORDINATOR                |                      |       |       |       |            |          |        |      |            |
|  28 |    PX SEND QC (RANDOM)          | :TQ20004             |     6 |   804 |       |  1748   (3)| 00:00:21 |  Q2,04 | P->S | QC (RAND)  |
|* 29 |     HASH JOIN                   |                      |     6 |   804 |       |  1748   (3)| 00:00:21 |  Q2,04 | PCWP |            |
|  30 |      PX RECEIVE                 |                      |     6 |   720 |       |  1745   (3)| 00:00:21 |  Q2,04 | PCWP |            |
|  31 |       PX SEND BROADCAST         | :TQ20003             |     6 |   720 |       |  1745   (3)| 00:00:21 |  Q2,03 | P->P | BROADCAST  |
|  32 |        MERGE JOIN ANTI NA       |                      |     6 |   720 |       |  1745   (3)| 00:00:21 |  Q2,03 | PCWP |            |
|  33 |         SORT JOIN               |                      |   557 | 61827 |       |  1736   (3)| 00:00:21 |  Q2,03 | PCWP |            |
|* 34 |          HASH JOIN RIGHT ANTI NA|                      |   557 | 61827 |       |  1735   (3)| 00:00:21 |  Q2,03 | PCWP |            |
|  35 |           PX RECEIVE            |                      |  1059 |  5295 |       |     3   (0)| 00:00:01 |  Q2,03 | PCWP |            |
|  36 |            PX SEND BROADCAST    | :TQ20000             |  1059 |  5295 |       |     3   (0)| 00:00:01 |  Q2,00 | P->P | BROADCAST  |
|  37 |             PX BLOCK ITERATOR   |                      |  1059 |  5295 |       |     3   (0)| 00:00:01 |  Q2,00 | PCWC |            |
|* 38 |              TABLE ACCESS FULL  | RPT_ZM_RATE          |  1059 |  5295 |       |     3   (0)| 00:00:01 |  Q2,00 | PCWP |            |
|  39 |           MERGE JOIN ANTI NA    |                      | 55738 |  5769K|       |  1732   (3)| 00:00:21 |  Q2,03 | PCWP |            |
|  40 |            SORT JOIN            |                      |  5573K|   515M|  1643M|  1631   (2)| 00:00:20 |  Q2,03 | PCWP |            |
|  41 |             PX BLOCK ITERATOR   |                      |  5573K|   515M|       |  1614   (1)| 00:00:20 |  Q2,03 | PCWC |            |
|* 42 |              TABLE ACCESS FULL  | TMP_ITEM_AGGR_EX_691 |  5573K|   515M|       |  1614   (1)| 00:00:20 |  Q2,03 | PCWP |            |
|* 43 |            SORT UNIQUE          |                      |   421K|  3704K|    16M|   101   (5)| 00:00:02 |  Q2,03 | PCWP |            |
|  44 |             PX RECEIVE          |                      |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q2,03 | PCWP |            |
|  45 |              PX SEND BROADCAST  | :TQ20001             |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q2,01 | P->P | BROADCAST  |
|  46 |               PX BLOCK ITERATOR |                      |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q2,01 | PCWC |            |
|* 47 |                TABLE ACCESS FULL| RPT_PRODUCT_RATE     |   421K|  3704K|       |    96   (0)| 00:00:02 |  Q2,01 | PCWP |            |
|* 48 |         SORT UNIQUE             |                      | 22695 |   199K|       |     9  (12)| 00:00:01 |  Q2,03 | PCWP |            |
|  49 |          PX RECEIVE             |                      | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q2,03 | PCWP |            |
|  50 |           PX SEND BROADCAST     | :TQ20002             | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q2,02 | P->P | BROADCAST  |
|  51 |            PX BLOCK ITERATOR    |                      | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q2,02 | PCWC |            |
|* 52 |             TABLE ACCESS FULL   | RPT_OFFER_RATE       | 22695 |   199K|       |     8   (0)| 00:00:01 |  Q2,02 | PCWP |            |
|  53 |      PX BLOCK ITERATOR          |                      |  6083 | 85162 |       |     3   (0)| 00:00:01 |  Q2,04 | PCWC |            |
|* 54 |       TABLE ACCESS FULL         | TMP_ZM_ONLY_RATE     |  6083 | 85162 |       |     3   (0)| 00:00:01 |  Q2,04 | PCWP |            |
---------------------------------------------------------------------------------------------------------------------------------------------

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

   4 - access("A"."ACCT_ITEM_TYPE_ID"="B"."ACCT_ITEM_TYPE_ID")
  12 - access(:Z>=:Z AND :Z<=:Z)
  13 - access(INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID") AND
              INTERNAL_FUNCTION("A"."PRODUCT_ID")=INTERNAL_FUNCTION("PRODUCT_ID"))
       filter((INTERNAL_FUNCTION("A"."PRODUCT_ID")=INTERNAL_FUNCTION("PRODUCT_ID") AND
              INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID")))
  17 - access(:Z>=:Z AND :Z<=:Z)
  18 - access(INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID") AND
              INTERNAL_FUNCTION("A"."OFFER_CD")=INTERNAL_FUNCTION("OFFER_ID"))
       filter((INTERNAL_FUNCTION("A"."OFFER_CD")=INTERNAL_FUNCTION("OFFER_ID") AND
              INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID")))
  22 - access(:Z>=:Z AND :Z<=:Z)
  26 - access(:Z>=:Z AND :Z<=:Z)
  29 - access("A"."ACCT_ITEM_TYPE_ID"="B"."ACCT_ITEM_TYPE_ID")
  34 - access("A"."ACCT_ITEM_TYPE_ID"="ACCT_ITEM_TYPE_ID")
  38 - access(:Z>=:Z AND :Z<=:Z)
  42 - access(:Z>=:Z AND :Z<=:Z)
  43 - access(INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID") AND
              INTERNAL_FUNCTION("A"."PRODUCT_ID")=INTERNAL_FUNCTION("PRODUCT_ID"))
       filter((INTERNAL_FUNCTION("A"."PRODUCT_ID")=INTERNAL_FUNCTION("PRODUCT_ID") AND
              INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID")))
  47 - access(:Z>=:Z AND :Z<=:Z)
  48 - access(INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID") AND
              INTERNAL_FUNCTION("A"."OFFER_CD")=INTERNAL_FUNCTION("OFFER_ID"))
       filter((INTERNAL_FUNCTION("A"."OFFER_CD")=INTERNAL_FUNCTION("OFFER_ID") AND
              INTERNAL_FUNCTION("A"."ACCT_ITEM_TYPE_ID")=INTERNAL_FUNCTION("ACCT_ITEM_TYPE_ID")))
  52 - access(:Z>=:Z AND :Z<=:Z)
  54 - access(:Z>=:Z AND :Z<=:Z)

 

 

很明显,原库的执行计划要好的,通过对比执行计划,我们发现:性能较差的SQL的执行计划中,not in 被改写成了not exits,进行了一些filter操作。而性能较高的SQL的执行计划,则是选择了ANTI Join。
问题是原来为什么ok ?存储迁移之后就有问题了呢 ?第一感觉可能是调整了优化器参数,检查发现果然是:

SYS@rptdb1> show parameter optimizer

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_optimizer_adaptive_cursor_sharing   boolean     FALSE
_optimizer_extended_cursor_sharing   string      NONE
_optimizer_extended_cursor_sharing_r string      NONE
el
_optimizer_null_aware_antijoin       boolean     FALSE
_optimizer_use_feedback              boolean     FALSE
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_dynamic_sampling           integer     2
optimizer_features_enable            string      11.2.0.2
optimizer_index_caching              integer     0
optimizer_index_cost_adj             integer     100
optimizer_mode                       string      ALL_ROWS
optimizer_secure_view_merging        boolean     TRUE
optimizer_use_invisible_indexes      boolean     FALSE
optimizer_use_pending_statistics     boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE
SYS@rptdb1>
SYS@rptdb1> alter session set "_optimizer_null_aware_antijoin"=true;

Session altered.

通过将该参数改回默认值,测试一切正常。 这里我主要是通过SQLT来解决该SQL的性能问题,首先创建一个SQL profile,然后修改SQL profile的查询块信息即可,如下:

q'[OPT_PARAM('_optimizer_null_aware_antijoin' 'true')]',
q'[OPT_PARAM('_optimizer_extended_cursor_sharing' 'none')]',
q'[OPT_PARAM('_optimizer_extended_cursor_sharing_rel' 'none')]',
q'[OPT_PARAM('_optimizer_adaptive_cursor_sharing' 'false')]',
q'[OPT_PARAM('_optimizer_use_feedback' 'false')]',

通过调整之后,SQL性能恢复正常。 虽然这是一个很常见的问题,然而我却是第一次在生产中碰见,下面进行一个简单的测试。
说明:测试脚本来自google。
—For 10.2.0.5

www.killdb.com> create table t1
  2  as select
  3  cast(rownum as int) a,
  4  cast(rownum+10 as int) b,
  5  cast(dbms_random.string('i',10) as varchar2(10)) c
  6  from dual connect by level<=10000;

Table created.

www.killdb.com> create table t2
  2  as select
  3  cast(rownum as int) a,
  4  cast(rownum+10 as int) b,
  5  cast(dbms_random.string('i',10) as varchar2(10)) c
  6  from dual connect by level<=9980;

Table created.

www.killdb.com>
www.killdb.com> set autot traceonly exp
www.killdb.com> analyze table t1 compute statistics;

Table analyzed.

www.killdb.com> analyze table t2 compute statistics;

Table analyzed.

www.killdb.com> select /*SQL_1*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 895956251

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  9999 |   126K| 60407   (1)| 00:12:05 |
|*  1 |  FILTER            |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| T1   | 10000 |   126K|    12   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T2   |     1 |     3 |    12   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE
              LNNVL("A"<>:B1)))
   3 - filter(LNNVL("A"<>:B1))

www.killdb.com> alter table t2 modify a not null ;

Table altered.

www.killdb.com> select /*SQL_2*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 895956251

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  9999 |   126K| 60407   (1)| 00:12:05 |
|*  1 |  FILTER            |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| T1   | 10000 |   126K|    12   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T2   |     1 |     3 |    12   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE
              LNNVL("A"<>:B1)))
   3 - filter(LNNVL("A"<>:B1))

www.killdb.com> create index idx_t2_a on t2(a);

Index created.

www.killdb.com> create index idx_t1_a on t1(a);

Index created.

www.killdb.com> select /*SQL_3*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 377637984

----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |  9999 |   126K| 35333   (1)| 00:07:04 |
|*  1 |  FILTER               |          |       |       |            |          |
|   2 |   TABLE ACCESS FULL   | T1       | 10000 |   126K|    12   (0)| 00:00:01 |
|*  3 |   INDEX FAST FULL SCAN| IDX_T2_A |     1 |     3 |     7   (0)| 00:00:01 |
----------------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE LNNVL("A"<>:B1)))
   3 - filter(LNNVL("A"<>:B1))

www.killdb.com>

我们可以看到,仍然没有走办连接,还是走filter了,这里的类似nest loop,很明显效率很低,其原因是需要用T1表的每条记录去和T2 返回的结果集进行匹配。那么有没有办法让SQL走半连接呢 ? 肯定是可以的,如下:

www.killdb.com> alter table t1 modify a not null ;

Table altered.

www.killdb.com> select /*SQL_4*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 1490751970

----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |    20 |   320 |    20   (5)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT ANTI |          |    20 |   320 |    20   (5)| 00:00:01 |
|   2 |   INDEX FAST FULL SCAN| IDX_T2_A |  9980 | 29940 |     7   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL   | T1       | 10000 |   126K|    12   (0)| 00:00:01 |
----------------------------------------------------------------------------------

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

   1 - access("A"="A")

我们可以看到,走半连接之后,效率明显要高的多。当然,这里不对t1表进行not null操作也可以进行优化。
—-for 11.2.0.2 test

[ora11g@localhost ~]$ sqlplus "/as sysdba"

SQL*Plus: Release 11.2.0.2.0 Production on Sat Apr 18 22:59:32 2015

Copyright (c) 1982, 2010, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

www.killdb.com> conn roger/roger
Connected.
www.killdb.com>

SQL> create table t1
  2  as select
  3  cast(rownum as int) a,
  4  cast(rownum+10 as int) b,
  5  cast(dbms_random.string('i',10) as varchar2(10)) c
  6  from dual connect by level<=10000;

Table created.

SQL> create table t2
  2  as select
  3  cast(rownum as int) a,
  4  cast(rownum+10 as int) b,
  5  cast(dbms_random.string('i',10) as varchar2(10)) c
  6  from dual connect by level<=9980;

Table created.

SQL> analyze table t1 compute statistics ;

Table analyzed.

SQL> analyze table t2 compute statistics;

Table analyzed.

SQL> set autot traceonly exp
SQL> select /*SQL_1*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 2739594415

--------------------------------------------------------------------------------
| Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |   100 |  1600 |    23   (5)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT ANTI NA|      |   100 |  1600 |    23   (5)| 00:00:01 |
|   2 |   TABLE ACCESS FULL     | T2   |  9980 | 29940 |    11   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL     | T1   | 10000 |   126K|    11   (0)| 00:00:01 |
--------------------------------------------------------------------------------

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

   1 - access("A"="A")

SQL> alter session set "_optimizer_null_aware_antijoin"=false;

Session altered.

SQL> select /*SQL_2*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 895956251

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |  9999 |   126K| 55478   (1)| 00:11:06 |
|*  1 |  FILTER            |      |       |       |            |          |
|   2 |   TABLE ACCESS FULL| T1   | 10000 |   126K|    11   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T2   |     1 |     3 |    11   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE
              LNNVL("A"<>:B1)))
   3 - filter(LNNVL("A"<>:B1))

SQL> alter table t2 modify a not null;

Table altered.

SQL> create index idx_t2_a on t2(a);

Index created.

SQL> create index idx_t1_a on t1(a);

Index created.

SQL>
SQL> alter session set "_optimizer_null_aware_antijoin"=true;

Session altered.

SQL>  select /*SQL_3*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 2568882110

-------------------------------------------------------------------------------------
| Id  | Operation                | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |          |   100 |  1600 |    19   (6)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT ANTI SNA|          |   100 |  1600 |    19   (6)| 00:00:01 |
|   2 |   INDEX FAST FULL SCAN   | IDX_T2_A |  9980 | 29940 |     7   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL      | T1       | 10000 |   126K|    11   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

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

   1 - access("A"="A")

SQL> alter session set "_optimizer_null_aware_antijoin"=false;

Session altered.

SQL> select /*SQL_3*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 377637984

----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |  9999 |   126K| 35396   (2)| 00:07:05 |
|*  1 |  FILTER               |          |       |       |            |          |
|   2 |   TABLE ACCESS FULL   | T1       | 10000 |   126K|    11   (0)| 00:00:01 |
|*  3 |   INDEX FAST FULL SCAN| IDX_T2_A |     1 |     3 |     7   (0)| 00:00:01 |
----------------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT 0 FROM "T2" "T2" WHERE LNNVL("A"<>:B1)))
   3 - filter(LNNVL("A"<>:B1))

SQL>  alter table t1 modify a not null ;

Table altered.

SQL> select /*SQL_3*/ c from t1 where a not in (select a from t2) ;

Execution Plan
----------------------------------------------------------
Plan hash value: 1490751970

----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |   100 |  1600 |    19   (6)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT ANTI |          |   100 |  1600 |    19   (6)| 00:00:01 |
|   2 |   INDEX FAST FULL SCAN| IDX_T2_A |  9980 | 29940 |     7   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL   | T1       | 10000 |   126K|    11   (0)| 00:00:01 |
----------------------------------------------------------------------------------

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

   1 - access("A"="A")

实际上,通过我们测试可以发现,本质上应用SQL出问题,不是我们调整参数的问题,而是应用SQL写法不规范导致。或者说应用表结构设计存在缺陷导致。实际上该SQL,我们不需要调整隐含参数,通过对表的column 添加非空约束即可。

Related posts:

  1. 10g中distinct加强以及anti jion,semi jion
  2. about subquery unnest/push pred
此条目发表在 未分类 分类目录。将固定链接加入收藏夹。

评论功能已关闭。