使用/*+ no_expand */避免执行路径中的CONCATENATION

 

昨天的一次SQL优化过程,仅作记录。

 

背景是在一台11gR2的机器上,用户反映一个查询操作非常慢,基本都要20~30分钟才能有结果。经过仔细查看该SQL的执行计划,发现由于SQL中使用了or,导致CBO走出了一个非常糟糕的CONCATENATION路径。因为SQL本身是通过程序动态生成的,开发人员不愿意进行大的调整,就采用了/*+ no_expand */提升的方式避免CBO选择CONCATENATION方式,调整之后执行时间提升到1分钟之内。

 

no_expand提示的说明是

The NO_EXPAND hint prevents the cost-based optimizer from considering OR-expansion for queries having OR conditions or IN-lists in the WHERE clause. Usually, the optimizer considers using OR expansion and uses this method if it decides that the cost is lower than not using it.

use_concat提示的说明是

The USE_CONCAT hint forces combined OR conditions in the WHERE clause of a query to be transformed into a compound query using the UNION ALL set operator. Generally, this transformation occurs only if the cost of the query using the concatenations is cheaper than the cost without them.

 

问题解决了,不过留下了一个疑点:在Oracle 11gR2中,在cost明显很高的情况下,CBO是不应该选用CONCATENATION的,在 wait4friend 的测试过程中,使用SQL*Plus或者GUI的开发工具执行该SQL,都不会生成CONCATENATION的执行计划,为了重现这个问题,必须使用/*+ use_concat */来模拟。那么问题就奇怪了,为什么通过程序提交过来的SQL总是会选择很差的计划?到底是什么因素导致CBO做出错误的选择,目前还没有找到原因。一个可能的原因是,开发人员使用的是ojdbc14.jar的驱动,不过尚未进行验证。

 

语句如下。红色部分是后面修改的,为了避免CBO选择CONCATENATION路径,使用了/*+ no_expand */提示。

SELECT COUNT (*)
  FROM (SELECT cu.customer_id, bi.bill_id
          FROM    (SELECT /*+ no_expand */ cu.customer_id
                     FROM ep_customer cu,
                          ep_cus_expands ex,
                          (SELECT id, project_id, name_alias
                             FROM no_card_channel) ch
                    WHERE     1 = 1
                          AND ex.create_time >= 20000101000000
                          AND ex.create_time <= 20121213235959
                          AND ex.TYPE = 'NC_CHANNEL'
                          AND ex.validity = 'true'
                          AND (   ex.ext_data = ch.project_id
                               OR ex.ext_data = ch.name_alias)
                          AND ex.customer_id = cu.customer_id) cu
               LEFT JOIN
                  (SELECT b.bill_id,
                          b.customer_id,
                          b.amount,
                          b.trans_id,
                          c.settle_time
                     FROM ep_bill b, ep_cup_certificate c
                    WHERE     b.status IN ('paid', 'void', 'refund')
                          AND c.pay_class = 'NC_PAY'
                          AND c.TYPE = 'purchase'
                          AND c.validity = 'true'
                          AND b.bill_id = c.bill_id
                   UNION ALL
                   SELECT b.bill_id,
                          b.customer_id,
                          b.amount,
                          b.trans_id,
                          '' settle_time
                     FROM ep_bill b
                    WHERE b.trans_id = '1382') bi
               ON cu.customer_id = bi.customer_id)
 WHERE bill_id IS NULL;
 

 

糟糕的执行计划

Plan hash value: 3646981028
 
---------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name               | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                    |       |       |       |   120K(100)|          |
|   1 |  SORT AGGREGATE            |                    |     1 |    83 |       |            |          |
|   2 |   CONCATENATION            |                    |       |       |       |            |          |
|   3 |    HASH JOIN               |                    |   517K|    40M|       | 61936   (1)| 00:12:24 |
|   4 |     TABLE ACCESS FULL      | NO_CARD_CHANNEL    |   130 |  3250 |       |     3   (0)| 00:00:01 |
|   5 |     FILTER                 |                    |       |       |       |            |          |
|   6 |      HASH JOIN RIGHT OUTER |                    |   653K|    36M|  1848K| 61929   (1)| 00:12:24 |
|   7 |       VIEW                 |                    | 78526 |   920K|       | 48749   (1)| 00:09:45 |
|   8 |        UNION-ALL           |                    |       |       |       |            |          |
|   9 |         HASH JOIN          |                    | 74882 |  3436K|  2928K| 28390   (1)| 00:05:41 |
|  10 |          TABLE ACCESS FULL | EP_CUP_CERTIFICATE | 74882 |  2047K|       |  5369   (1)| 00:01:05 |
|  11 |          TABLE ACCESS FULL | EP_BILL            |  1702K|    30M|       | 20366   (1)| 00:04:05 |
|  12 |         TABLE ACCESS FULL  | EP_BILL            |  3644 | 58304 |       | 20359   (1)| 00:04:05 |
|  13 |       HASH JOIN            |                    |   655K|    28M|    32M| 11287   (1)| 00:02:16 |
|  14 |        TABLE ACCESS FULL   | EP_CUS_EXPANDS     |   655K|    24M|       |  5595   (2)| 00:01:08 |
|  15 |        INDEX FAST FULL SCAN| P_CUSTOMER_ID      |  2654K|    15M|       |  1791   (1)| 00:00:22 |
|  16 |    HASH JOIN               |                    |     1 |    83 |       | 58518   (1)| 00:11:43 |
|  17 |     MERGE JOIN CARTESIAN   |                    |     1 |    43 |       | 52919   (1)| 00:10:36 |
|  18 |      FILTER                |                    |       |       |       |            |          |
|  19 |       HASH JOIN RIGHT OUTER|                    |     1 |    18 |  1848K| 52916   (1)| 00:10:35 |
|  20 |        VIEW                |                    | 78526 |   920K|       | 48749   (1)| 00:09:45 |
|  21 |         UNION-ALL          |                    |       |       |       |            |          |
|  22 |          HASH JOIN         |                    | 74882 |  3436K|  2928K| 28390   (1)| 00:05:41 |
|  23 |           TABLE ACCESS FULL| EP_CUP_CERTIFICATE | 74882 |  2047K|       |  5369   (1)| 00:01:05 |
|  24 |           TABLE ACCESS FULL| EP_BILL            |  1702K|    30M|       | 20366   (1)| 00:04:05 |
|  25 |          TABLE ACCESS FULL | EP_BILL            |  3644 | 58304 |       | 20359   (1)| 00:04:05 |
|  26 |        INDEX FAST FULL SCAN| P_CUSTOMER_ID      |  2654K|    15M|       |  1791   (1)| 00:00:22 |
|  27 |      BUFFER SORT           |                    |   130 |  3250 |       | 52919   (1)| 00:10:36 |
|  28 |       TABLE ACCESS FULL    | NO_CARD_CHANNEL    |   130 |  3250 |       |     3   (0)| 00:00:01 |
|  29 |     TABLE ACCESS FULL      | EP_CUS_EXPANDS     |   655K|    24M|       |  5595   (2)| 00:01:08 |
---------------------------------------------------------------------------------------------------------
正常情况下的执行计划
 
Plan hash value: 3689968997
 
--------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name               | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |                    |       |       |       | 60823 (100)|          |
|   1 |  SORT AGGREGATE           |                    |     1 |    97 |       |            |          |
|   2 |   NESTED LOOPS            |                    |  4979 |   471K|       | 60823   (1)| 00:12:10 |
|   3 |    FILTER                 |                    |       |       |       |            |          |
|   4 |     HASH JOIN OUTER       |                    |  3441 |   241K|       | 56150   (1)| 00:11:14 |
|   5 |      HASH JOIN            |                    |  3452 |   155K|       |  7399   (2)| 00:01:29 |
|   6 |       TABLE ACCESS FULL   | EP_CUS_EXPANDS     |  3452 |   134K|       |  5595   (2)| 00:01:08 |
|   7 |       INDEX FAST FULL SCAN| P_CUSTOMER_ID      |  2654K|    15M|       |  1791   (1)| 00:00:22 |
|   8 |      VIEW                 |                    | 78526 |  1993K|       | 48749   (1)| 00:09:45 |
|   9 |       UNION-ALL           |                    |       |       |       |            |          |
|  10 |        HASH JOIN          |                    | 74882 |  3436K|  2928K| 28390   (1)| 00:05:41 |
|  11 |         TABLE ACCESS FULL | EP_CUP_CERTIFICATE | 74882 |  2047K|       |  5369   (1)| 00:01:05 |
|  12 |         TABLE ACCESS FULL | EP_BILL            |  1702K|    30M|       | 20366   (1)| 00:04:05 |
|  13 |        TABLE ACCESS FULL  | EP_BILL            |  3644 | 58304 |       | 20359   (1)| 00:04:05 |
|  14 |    TABLE ACCESS FULL      | NO_CARD_CHANNEL    |     1 |    25 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
 
 

posted on 2012-12-14 15:45  wait4friend  阅读(2515)  评论(0编辑  收藏  举报