2016-07-28 104 views
1

我有这个复杂的SQL查询:SQL为什么不使用PK索引?

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。

+0

和表定义(可能有不匹配的类型) – vercelli

+0

似乎你的逻辑处理顺序错误,因为@sstan提到。这将停止这个查询工作 –

+0

@sstan改变having子句的顺序不会导致任何不同的效果。 DTPOLI和STAT_PRO_DET表对于两列都具有相同的数据项:数字。 – milheiros

回答

6

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

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

这些块可能位于缓冲区缓存中,但您仍然击中了两次,并且由于您会跳到索引和表格的不同部分,因此您越来越容易发生老化 - 这意味着即使您最终从相同的物理数据块中获取两行,也可能最终不得不从磁盘读取两次。

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

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

您的主键是强制执行参照完整性。它也可以用来快速检索特定的数据,但只有在适当的时候才能检索。优化器在决定何时和不适当时做得非常好。

+0

很好的解释!谢谢。 – milheiros

相关问题