2016-07-28 7 views
1

Ich habe diese komplizierte SQL-Abfrage:SQL Warum PK-Index nicht verwenden?

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; 

Der Primärschlüssel für dtpoli Tabelle ist dies:

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

Hier ist die erklären Plan:

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)) 

Beide Säulen sind Anzahl Datentyp . Mit dem Hinweis parallel(#) kann ich die Leistung verbessern, aber mein Fokus liegt auf dtpoli PK.

Ich kann nicht finden, warum diese Abfrage diesen Primärschlüsselindex nicht verwendet und einen vollständigen Tabellenscan in DTPOLI-Tabelle verwendet. Es ist, weil ich eine Group by Klausel habe? Ich verstehe es wirklich nicht. Irgendwelche Hilfe? Ich benutze Oracle 11gR2.

+0

Und Tabellendefinition (es könnte einen Unterschied zwischen den Typen geben) – vercelli

+0

Scheint, Sie haben die logische Verarbeitungsreihenfolge falsch als @sstan erwähnt. Was würde diese Abfrage stoppen –

+0

@ststan Änderung der Reihenfolge der having-Klausel verursachen keinen anderen Effekt. Sowohl die Tabellen DTPOLI als auch STAT_PRO_DET haben den gleichen Datentyp für beide Spalten: Zahl. – milheiros

Antwort

6

Es verwendet nicht den Index, weil es weniger effizient wäre, dies zu tun. Ein Index ist nützlich, wenn Sie einen kleinen Teil der Daten aus der Tabelle abrufen, aber wenn Sie eine Menge davon erhalten, wäre die Verwendung des Indexes langsamer.

Der Grund ist, dass das Finden der passenden Zeile im Index einen Plattenzugriff erfordert, um den Indexblock zu erhalten. Das gibt Ihnen die ROWID des Datensatzes und Sie benötigen dann einen anderen Datenträgerzugriff, um diesen Datenblock zu erhalten. Jeder Index und jeder Datenblock muss mindestens einmal und möglicherweise mehrmals gelesen werden.

Die Blöcke befinden sich zwar im Puffer-Cache, aber Sie treffen das immer noch zweimal, und weil Sie zu verschiedenen Teilen des Indexes und der Tabelle springen würden, erhöhen Sie die Wahrscheinlichkeit, dass die Dinge auslaufen - Das bedeutet, dass Sie selbst dann, wenn Sie zwei Zeilen aus demselben physischen Datenblock erhalten, diese möglicherweise zweimal von der Festplatte lesen müssen.

Ein vollständiger Tabellenscan ruft alle Datenblöcke für die Tabelle auf einmal ab, sodass sie nicht zweimal gelesen werden müssen und nicht zusätzlich die Indexblöcke lesen müssen.

Wenn Sie nur bezogen auf die Spalten im Primärschlüssel (oder einem anderen Index) wären, dann könnte ein vollständiger Index-Scan verwendet werden. Aber Sie rufen Non-Index-Daten wie poliagtb ab, sodass die Datenblöcke ebenfalls abgerufen werden müssen.

Ihr Primärschlüssel setzt die referenzielle Integrität durch. Es kann auch verwendet werden, um bestimmte Daten schnell, aber nur bei Bedarf abzurufen. Der Optimierer kann ziemlich gut entscheiden, wann dies zutrifft und was nicht.

+0

Tolle Erklärung! Vielen Dank. – milheiros