SQL为什么不使用PK索引?

时间:2016-07-28 14:47:07

标签: sql oracle indexing

我有这个复杂的SQL查询:

  SELECT f1 (d1.prdecdde),
         f2 (d1.prdecdde),
         f3 (d1.prdecdde),
         f4 (1, d1.prdecdde, d1.prdenpol),
         d1.prdeisin,
         f6 (d1.prdecdde, a.POLIRCTB),
         NVL (a.poliagtb, a.poliagta),
         d1.prdedtpr,
         prdeticu
    FROM (  SELECT prdecdde,
                   prdenpol,
                   prdeano,
                   SUM (NVL (prdeval, 0)) valantes,
                   NULL valdepois,
                   prdedtpr,
                   prdeticu,
                   prdeisin
              FROM stat_pro_det
             WHERE     prdedprv = '20151101'
                   AND prdecdde IN (700,
                                    100,
                                    610,
                                    600,
                                    710,
                                    900,
                                    910)
                   AND prdeval > 0
          GROUP BY prdecdde,
                   prdenpol,
                   prdeano,
                   prdedtpr,
                   prdeticu,
                   prdeisin
          UNION ALL
            SELECT prdecdde,
                   prdenpol,
                   prdeano,
                   NULL,
                   SUM (NVL (prdeval, 0)) valdepois,
                   prdedtpr,
                   prdeticu,
                   prdeisin
              FROM stat_pro_det
             WHERE     prdedprv = '20160727'
                   AND prdecdde IN (700,
                                    100,
                                    610,
                                    600,
                                    710,
                                    900,
                                    910)
                   AND prdeval > 0
          GROUP BY prdecdde,
                   prdenpol,
                   prdeano,
                   prdedtpr,
                   prdeticu,
                   prdeisin) d1,
         sgss.dtpoli a
   WHERE a.policdde = d1.prdecdde AND a.polinpol = d1.prdenpol
  HAVING SUM (NVL (d1.valdepois, 0) - NVL (d1.valantes, 0)) <> 0
GROUP BY d1.prdecdde,
         d1.prdenpol,
         d1.prdeano,
         a.polirctb,
         a.poliagta,
         a.poliagtb,
         d1.prdedtpr,
         d1.prdeticu,
         d1.prdeisin;

dtpoli表的主键是:

CREATE UNIQUE INDEX SGSS.PK_DTPOLI ON SGSS.DTPOLI
(POLICDDE, POLINPOL)

以下是解释计划:

Plan hash value: 1960385779

--------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name            | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                 | 19403 |  1705K|       |   113K  (1)| 00:00:05 |
|*  1 |  FILTER                            |                 |       |       |       |            |          |
|   2 |   HASH GROUP BY                    |                 | 19403 |  1705K|    38M|   113K  (1)| 00:00:05 |
|*  3 |    HASH JOIN                       |                 |   388K|    33M|    23M|   111K  (1)| 00:00:05 |
|   4 |     TABLE ACCESS FULL              | DTPOLI          |   618K|    16M|       |  6561   (7)| 00:00:01 |
|   5 |     VIEW                           |                 |   388K|    22M|       |   103K  (1)| 00:00:05 |
|   6 |      UNION-ALL                     |                 |       |       |       |            |          |
|   7 |       HASH GROUP BY                |                 |   194K|  9304K|    13M| 52044   (1)| 00:00:03 |
|   8 |        INLIST ITERATOR             |                 |       |       |       |            |          |
|*  9 |         TABLE ACCESS BY INDEX ROWID| STAT_PRO_DET    |   194K|  9304K|       | 50003   (1)| 00:00:02 |
|* 10 |          INDEX RANGE SCAN          | STAT_PRO_DET_03 |   198K|       |       |   790   (2)| 00:00:01 |
|  11 |       HASH GROUP BY                |                 |   193K|  9264K|    13M| 51818   (1)| 00:00:03 |
|  12 |        INLIST ITERATOR             |                 |       |       |       |            |          |
|* 13 |         TABLE ACCESS BY INDEX ROWID| STAT_PRO_DET    |   193K|  9264K|       | 49784   (1)| 00:00:02 |
|* 14 |          INDEX RANGE SCAN          | STAT_PRO_DET_03 |   197K|       |       |   783   (2)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------

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

   1 - filter(SUM(NVL("D1"."VALDEPOIS",0)-NVL("D1"."VALANTES",0))<>0)
   3 - access("POLICDDE"="D1"."PRDECDDE" AND "POLINPOL"="D1"."PRDENPOL")
   9 - filter("PRDEVAL">0)
  10 - access("PRDEDPRV"='20151101' AND ("PRDECDDE"=100 OR "PRDECDDE"=600 OR "PRDECDDE"=610 OR 
              "PRDECDDE"=700 OR "PRDECDDE"=710 OR "PRDECDDE"=900 OR "PRDECDDE"=910))
  13 - filter("PRDEVAL">0)
  14 - access("PRDEDPRV"='20160727' AND ("PRDECDDE"=100 OR "PRDECDDE"=600 OR "PRDECDDE"=610 OR 
              "PRDECDDE"=700 OR "PRDECDDE"=710 OR "PRDECDDE"=900 OR "PRDECDDE"=910))

两列都是数字数据类型。使用提示parallel(#)我可以改善效果,但我的重点是dtpoli PK

我无法找到为什么此查询不使用此主键索引并在DTPOLI表上使用全表扫描。这是因为我有一个Group by条款?我真的不明白。 有帮助吗? 我正在使用Oracle 11gR2。

1 个答案:

答案 0 :(得分:6)

它没有使用索引,因为这样做 效率更低。如果您从表中检索一小部分数据,索引很有用,但是当您获得大量数据时,使用索引会更慢。

原因是在索引中找到匹配的行需要磁盘访问才能获取索引块。这为您提供了数据记录的ROWID,然后您需要另一个磁盘访问来获取该数据块。每个索引和数据块必须至少读取一次,并且可能多次读取。

这些块可能位于缓冲区缓存中,但您仍然会两次触及,并且由于您正在跳转到索引和表格的不同部分,因此您增加了已经老化的东西 - 这意味着即使你最终从同一个物理数据块中获得两行,你最终也可能需要从磁盘读取两次。

全表扫描将一次性检索该表的所有数据块,因此它不必读取其中的任何数据块两次,并且没有额外的开销也可以读取索引块。

如果您引用主键(或任何其他索引)中的列,则可能会使用完整索引扫描。但是您要检索非索引数据,例如poliagtb,因此也必须检索数据块。

您的主键是强制参照完整性。它还可以用于快速检索特定数据,但仅在适当时使用。优化者可以很好地决定它何时适合并且不合适。