使用/*+ 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 |

--------------------------------------------------------------------------------------------------------
 
 

你可能感兴趣的:(concat)