2016-11-23 57 views
1

我繼承了這個查詢來重建它:SQL查詢重建問題

SELECT a.poclcdde, 
       a.poclnpol, 
       a.poclcdce, 
       a.poclcdcl, 
       a.poclnuor 
      FROM dtpocl a 
     WHERE  a.poclcdre = '02' 
       AND a.poclxope IN ('01', '02') 
       AND a.poclnuor = 
         (SELECT MAX (b.poclnuor) 
         FROM dtpocl b 
         WHERE  b.poclcdde = a.poclcdde 
           AND b.poclnpol = a.poclnpol 
           AND b.poclcdce = a.poclcdce 
           AND b.poclcdre = '02' 
           AND b.poclxope IN ('01', '02') 
           AND NVL (b.poclfecb, 99999999) = 
            (SELECT MAX (NVL (c.poclfecb, 99999999)) 
             FROM dtpocl c 
             WHERE  c.poclcdde = b.poclcdde 
              AND c.poclnpol = b.poclnpol 
              AND c.poclcdce = b.poclcdce 
              AND c.poclcdre = '02' 
              AND c.poclxope IN ('01', '02'))) 

我有這樣的解釋計劃:

Plan hash value: 94095463 

-------------------------------------------------------------------------------------------------- 
| Id | Operation     | Name  | Rows | Bytes |TempSpc| Cost (%CPU)| Time  | 
-------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |   | 6293 | 497K|  | 53434 (3)| 00:00:03 | 
| 1 | NESTED LOOPS    |   |  |  |  |   |   | 
| 2 | NESTED LOOPS    |   | 6293 | 497K|  | 53434 (3)| 00:00:03 | 
| 3 | VIEW      | VW_SQ_2 | 12340 | 626K|  | 41045 (4)| 00:00:02 | 
| 4 |  HASH GROUP BY   |   | 12340 | 602K| 792K| 41045 (4)| 00:00:02 | 
|* 5 |  HASH JOIN    |   | 12340 | 602K| 47M| 40911 (4)| 00:00:02 | 
| 6 |  VIEW     | VW_SQ_1 | 1555K| 29M|  | 23144 (4)| 00:00:01 | 
| 7 |  HASH GROUP BY   |   | 1555K| 40M| 65M| 23144 (4)| 00:00:01 | 
|* 8 |   TABLE ACCESS FULL | DTPOCL | 1555K| 40M|  | 12793 (4)| 00:00:01 | 
|* 9 |  TABLE ACCESS FULL  | DTPOCL | 1555K| 44M|  | 12801 (4)| 00:00:01 | 
|* 10 | INDEX RANGE SCAN   | PK_DTPOCL |  1 |  |  |  1 (0)| 00:00:01 | 
|* 11 | TABLE ACCESS BY INDEX ROWID| DTPOCL |  1 | 29 |  |  2 (0)| 00:00:01 | 
-------------------------------------------------------------------------------------------------- 

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

    5 - access("MAX(NVL(C.POCLFECB,99999999))"=NVL("POCLFECB",'99999999') AND 
       "ITEM_1"="POCLCDDE" AND "ITEM_2"="POCLNPOL" AND "ITEM_3"="POCLCDCE") 
    8 - filter("POCLCDRE"='02' AND ("POCLXOPE"='01' OR "POCLXOPE"='02')) 
    9 - filter("POCLCDRE"='02' AND ("POCLXOPE"='01' OR "POCLXOPE"='02')) 
    10 - access("ITEM_4"="POCLCDDE" AND "ITEM_5"="POCLNPOL" AND "ITEM_6"="POCLCDCE" AND 
       "POCLNUOR"="MAX(B.POCLNUOR)") 
    11 - filter("POCLCDRE"='02' AND ("POCLXOPE"='01' OR "POCLXOPE"='02')) 

乍一看,我可以想像,這是一個錯誤的查詢,因爲:爲什麼我們需要爲同一個表執行另外兩個子查詢? 我需要的是dtpocl表中的所有記錄(此條件爲a.poclcdre = '02' AND a.poclxope IN ('01', '02')),他們的最大值爲poclnuor,最大值爲poclfecb

我試圖將2個聚合函數相同的查詢,如:

SELECT a.poclcdde, 
       a.poclnpol, 
       a.poclcdce, 
       a.poclcdcl, 
       MAX (a.poclnuor), 
       MAX (NVL (a.poclfecb, 99999999)) 
      FROM dtpocl a 
      WHERE a.poclcdre = '02' AND a.poclxope IN ('01', '02') 
     GROUP BY a.poclcdde, 
       a.poclnpol, 
       a.poclcdce, 
       a.poclcdcl 

,但我得到比原來的查詢與和的25.654成本更多的記錄。 dtpocl表有3.025.510行。

我們可以做些什麼來改善性能和查詢可讀性?謝謝。

+0

提供樣本數據和您的預期結果,這對其他人更容易清除您的疑問。 – Viki888

+0

「dtpocl」有哪些列是唯一的? –

+0

PK是poclcdde,poclnpol,poclcdce和poclnuor – milheiros

回答

2

您可以使用分析功能來發現你感興趣的poclnuor

SELECT 
    * 
FROM 
(
    SELECT 
    dtpocl.*, 
    MAX(poclnuor) 
     KEEP (DENSE_RANK FIRST ORDER BY poclfecb DESC NULLS FIRST) 
     OVER (PARTITION BY poclcdde, poclnpol, poclcdce) 
     AS target_poclnuor 
    FROM 
    dtpocl 
    WHERE 
     poclcdre = '02' 
    AND poclxope IN ('01', '02') 
) 
    sorted 
WHERE 
    poclnuor = target_poclnuor 

我從這裏的語法... https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions056.htm

你可能需要一個單一的指標覆蓋(poclcdde, poclnpol, poclcdce, poclfecb DESC, poclnuor DESC)

編輯: OP證實PK爲(poclcdde, poclnpol, poclcdce, poclnuor)

我不知道這是任何好轉,但我們知道的PK是否意味着這是一種替代...

SELECT 
    poclcdde, 
    poclnpol, 
    poclcdce, 
    MAX(poclcdcl) 
    KEEP (RANK FIRST 
      ORDER BY poclfecb DESC NULLS FIRST, 
        poclnuor DESC 
    ) 
     AS poclcdcl, 
    MAX(poclnuor) 
    KEEP (RANK FIRST 
      ORDER BY poclfecb DESC NULLS FIRST, 
        poclnuor DESC 
    ) 
     AS poclnuor 
FROM 
    dtpocl 
WHERE 
     poclcdre = '02' 
    AND poclxope IN ('01', '02') 
GROUP BY 
    poclcdde, 
    poclnpol, 
    poclcdce 

或者......

SELECT 
    sorted.* 
FROM 
(
    SELECT 
    ROW_NUMBER() 
     OVER (PARTITION BY poclcdde, poclnpol, poclcdce 
       ORDER BY poclfecb DESC NULLS FIRST, 
         poclnuor DESC 
    ) 
     AS seqnum 
    dtpocl.* 
    FROM 
    dtpocl 
    WHERE 
     poclcdre = '02' 
    AND poclxope IN ('01', '02') 
) 
    sorted 
WHERE 
    seqnum = 1 
+2

這看起來非常好。將WHERE poclcdre ='02'和poclxope IN('01','02')'添加到您的內部查詢中。 –

+0

@ThorstenKettner - 謝謝,不錯的地方:) – MatBailie

+0

謝謝你們。但是這個新的查詢在解釋計劃中具有較低的成本價值(一半),但是較高的字節數。兩個查詢都採用相同的執行時間。也許創建一個新的索引。但是這個不用:CREATE INDEX testIndex ON dtpocl(poclcdre,poclxope)' – milheiros

0

這是怎麼回事?

-- PK is poclcdde, poclnpol, poclcdce & poclnuor 

SELECT a.poclcdde, 
     a.poclnpol, 
     a.poclcdce, 
     a.poclcdcl, 
     a.poclnuor, 
     a.poclfecb 
    FROM dtpocl a 
WHERE a.poclcdre = '02' 
    AND a.poclxope IN ('01', '02') 
    AND a.poclnuor = 
     (SELECT MAX (b.poclnuor) 
     FROM dtpocl b 
     WHERE b.poclcdde = a.poclcdde 
      AND b.poclnpol = a.poclnpol 
      AND b.poclcdce = a.poclcdce 
      AND b.poclnuor = a.poclnuor 
      AND b.poclcdre = a.poclcdre 
      AND b.poclxope = a.poclxope) 
    AND NVL (a.poclfecb, 99999999) = -- Here you can only use a.poclfecb and not b.poclfecb 
     (SELECT MAX (NVL (c.poclfecb, 99999999)) 
     FROM dtpocl c 
     WHERE c.poclcdde = a.poclcdde 
      AND c.poclnpol = a.poclnpol 
      AND c.poclcdce = a.poclcdce 
      AND c.poclnuor = a.poclnuor 
      AND c.poclcdre = a.poclcdre 
      AND c.poclxope = a.poclxope) 
+0

根據數據,OP的查詢可以給出與您的查詢不同的結果。例如,對於數據'(id,poclfecb,pocnuor)'='(1,5,2),(2,4,2)',您的查詢只返回第1行,但原始查詢返回兩行。 *(沒有更多的信息,這是不可能分辨這種差異是否重要。)* – MatBailie

+0

PK是poclcdde,poclnpol&poclcdce和poclnuor – milheiros

+0

這種差異很重要。我用這個解決方案得到更多的行,而MatBailie是正確的。注意:'b.poclfecb'必須在'dtpocl b'的查詢裏面。 – milheiros