SQL查询重建问题

时间:2016-11-23 10:55:35

标签: sql aggregate-functions oracle12c

我继承了这个查询来重建它:

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

我试图在同一个查询中对两个聚合函数进行分组,如下所示:

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行。

我们可以采取哪些措施来提高性能和查询可读性?感谢。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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)