为什么这个SELECT语句需要两个多小时?

时间:2015-11-26 15:37:07

标签: sql oracle performance oracle11g query-optimization

我有两张桌子A& B. A有6,760,636条记录,B有452,175,960条记录。这是我正在使用的SELECT语句:

SELECT  /*+ parallel (T,1) */
         T.*
     FROM     TABLE_A T,
              TABLE_B P 
    WHERE     T.DESTINATION = P.DESTINATION 
          AND T.SAIL_DATE = P.SAIL_DATE 
          AND T.PACKAGE_TYPE = P.PACKAGE_TYPE 
          AND T.CABIN_CATEGORY = P.CABIN_CATEGORY 
          AND T.BOOKING_SOURCE = P.BOOKING_SOURCE 
          AND T.FARE_TYPE = P.FARE_TYPE 
          AND T.POST_DATE = P.POST_DATE;

我尝试在TABLE_A上创建索引,但仍然不考虑INDEX并进行全表扫描。

上面的EXPLAIN PLAN是

| Id  | Operation                    | Name                      | Rows  | Bytes | Cost (%CPU)|    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                           |  6760K|  1805M|   747K  (1)|        |      |            |
|   1 |  SORT AGGREGATE              |                           |     1 |    48 |            |        |      |            |
|   2 |   TABLE ACCESS BY INDEX ROWID| CL_PRICING_CONTROLS       |     1 |    48 |     2   (0)|        |      |            |
|   3 |    INDEX RANGE SCAN          | CL_PRICING_CONTROLS_IX3   |     1 |       |     1   (0)|        |      |            |
|   4 |  PX COORDINATOR              |                           |       |       |            |        |      |            |
|   5 |   PX SEND QC (RANDOM)        | :TQ10002                  |  6760K|  1805M|   747K  (1)|  Q1,02 | P->S | QC (RAND)  |
|   6 |    HASH JOIN                 |                           |  6760K|  1805M|   747K  (1)|  Q1,02 | PCWP |            |
|   7 |     PX RECEIVE               |                           |  6760K|  1437M|  1443   (1)|  Q1,02 | PCWP |            |
|   8 |      PX SEND HASH            | :TQ10001                  |  6760K|  1437M|  1443   (1)|  Q1,01 | P->P | HASH       |
|   9 |       PX BLOCK ITERATOR      |                           |  6760K|  1437M|  1443   (1)|  Q1,01 | PCWC |            |
|  10 |        TABLE ACCESS FULL     | TMP_RES_PRICE_CONTROL_111 |  6760K|  1437M|  1443   (1)|  Q1,01 | PCWP |            |
|  11 |     BUFFER SORT              |                           |       |       |            |  Q1,02 | PCWC |            |
|  12 |      PX RECEIVE              |                           |   450M|    23G|   746K  (1)|  Q1,02 | PCWP |            |
|  13 |       PX SEND HASH           | :TQ10000                  |   450M|    23G|   746K  (1)|        | S->P | HASH       |
|  14 |        INDEX FULL SCAN       | CL_PRICING_CONTROLS_IX1   |   450M|    23G|   746K  (1)|        |      |            |

我在两个表上尝试了并行查询,如下所示

SELECT  /*+ PARALLEL(T, 32)  PARALLEL(P, 32)*/
         T.*
     FROM     TABLE_A T,
              TABLE_B P 
    WHERE     T.DESTINATION = P.DESTINATION 
          AND T.SAIL_DATE = P.SAIL_DATE 
          AND T.PACKAGE_TYPE = P.PACKAGE_TYPE 
          AND T.CABIN_CATEGORY = P.CABIN_CATEGORY 
          AND T.BOOKING_SOURCE = P.BOOKING_SOURCE 
          AND T.FARE_TYPE = P.FARE_TYPE 
          AND T.POST_DATE = P.POST_DATE;

但是这会导致如下所示的EXPLAIN PLAN,我看到CPU的成本较低,但仍需要两个小时。

| Id  | Operation                    | Name                      | Rows  | Bytes | Cost (%CPU)|    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                           |  6760K|  1805M| 59345   (1)|        |      |            |
|   1 |  SORT AGGREGATE              |                           |     1 |    48 |            |        |      |            |
|   2 |   TABLE ACCESS BY INDEX ROWID| CL_PRICING_CONTROLS       |     1 |    48 |     2   (0)|        |      |            |
|   3 |    INDEX RANGE SCAN          | CL_PRICING_CONTROLS_IX3   |     1 |       |     1   (0)|        |      |            |
|   4 |  PX COORDINATOR              |                           |       |       |            |        |      |            |
|   5 |   PX SEND QC (RANDOM)        | :TQ10002                  |  6760K|  1805M| 59345   (1)|  Q1,02 | P->S | QC (RAND)  |
|   6 |    HASH JOIN BUFFERED        |                           |  6760K|  1805M| 59345   (1)|  Q1,02 | PCWP |            |
|   7 |     PX RECEIVE               |                           |  6760K|  1437M|  1443   (1)|  Q1,02 | PCWP |            |
|   8 |      PX SEND HASH            | :TQ10000                  |  6760K|  1437M|  1443   (1)|  Q1,00 | P->P | HASH       |
|   9 |       PX BLOCK ITERATOR      |                           |  6760K|  1437M|  1443   (1)|  Q1,00 | PCWC |            |
|  10 |        TABLE ACCESS FULL     | TMP_RES_PRICE_CONTROL_111 |  6760K|  1437M|  1443   (1)|  Q1,00 | PCWP |            |
|  11 |     PX RECEIVE               |                           |   450M|    23G| 57858   (1)|  Q1,02 | PCWP |            |
|  12 |      PX SEND HASH            | :TQ10001                  |   450M|    23G| 57858   (1)|  Q1,01 | P->P | HASH       |
|  13 |       PX BLOCK ITERATOR      |                           |   450M|    23G| 57858   (1)|  Q1,01 | PCWC |            |
|  14 |        TABLE ACCESS FULL     | CL_PRICING_CONTROLS       |   450M|    23G| 57858   (1)|  Q1,01 | PCWP |            |

1 个答案:

答案 0 :(得分:1)

请查看您的查询,特别是其WHERE子句。它完全由连接条件组成。它可以使用ANSI-92语法重写:

SELECT  /*+ parallel (T,1) */
         T.*
FROM     TABLE_A T
          inner join TABLE_B P 
on     T.DESTINATION = P.DESTINATION 
      AND T.SAIL_DATE = P.SAIL_DATE 
      AND T.PACKAGE_TYPE = P.PACKAGE_TYPE 
      AND T.CABIN_CATEGORY = P.CABIN_CATEGORY 
      AND T.BOOKING_SOURCE = P.BOOKING_SOURCE 
      AND T.FARE_TYPE = P.FARE_TYPE 
      AND T.POST_DATE = P.POST_DATE;

因此必须考虑每个表中的每一行。显然,全表扫描是唯一合理的访问路径。

在JOIN子句中的所有列上构建复合索引不太可能改变这一点。您正在从TABLE_A中选择所有列,因此数据库无论如何都需要访问该表。

除非两个表之间的交集中的记录数非常小,否则在多块读取中读取表将更有效,而不是使用表行查找进行索引扫描。实际上,您正在选择五亿行表中所有行中的六分之一。索引如何加快速度?

顺便说一句,您是如何决定并行度的?您的服务器有多少CPU?还有哪些其他进程同时运行? MAX_PARALLEL_SERVERS的值是多少? Find out more