Oracle 查询性能——多个复杂的窗口函数

Posted

技术标签:

【中文标题】Oracle 查询性能——多个复杂的窗口函数【英文标题】:Oracle Query Performance -- Multiple Complex Window Functions 【发布时间】:2019-10-15 19:18:29 【问题描述】:

这个查询一直是我存在的祸根。它在一个大约有 6 亿行的表上。该表未分区或索引。

我有 24 个用于历史趋势的数据表。我不得不调整代码,现在需要重新运行。每个月需要运行 2-3 个小时。我最近刚刚尝试一次运行 24 个查询.. 而我的 DBA.. 不高兴(陷入整个数据库)

我尝试过分区和索引,但没有看到性能提升。我尝试了不同级别 CTE 的不同方法.. 或子选择.. 没有运气... 因为 UCID/CALLIDS 中的差距.. 这里有很多时间逻辑..

    WITH
  UCID
  AS
    (SELECT /*+ PARALLEL(8) */
      --REGULAR FIELDS
      SEGSTART + (DISPTIME / 86400) CALLSTART
     ,SEGSTART +
      ((DISPTIME + ANSHOLDTIME + talktime) / 86400) +
      NvL(
        (CASE
           WHEN ORIGLOGIN IS NOT NULL AND
                ANSLOGIN IS NULL
           THEN
             (CONSULTTIME + ORIGHOLDTIME) / 86400
         END)
       ,0) CALLSTOP
     -- +NvL((cASE WHEN ORIGLOGIN IS NOT NULL AND ANSLOGIN IS NULL THEN CONSULTTIME/86400 END),0)CALLSTOP
     ,SEGSTART
     ,SEGSTOP
     ,split1
     ,UCID
     ,DIALED_NUM
     ,CALLING_PTY
     ,TRANSFERRED
     ,CALL_DTL_REC_ID
     ,CMSHOST COMPLEX_CMSHOST
     ,CALLID COMPLEX_CALLID
     ,anslogin n_anslogin
     ,origlogin n_origlogin
     --UCID WINDOW MATCHES
     ,LAST_VALUE(a.ASAIUUI)
        IGNORE NULLS
        OVER(
          PARTITION BY UCID
                      ,SEGSTART) ASAIUUI
     ,LAST_VALUE(a.ORIGLOGIN)
        IGNORE NULLS
        OVER(
          PARTITION BY UCID
                      ,SEGSTART) ORIGLOGIN
     ,LAST_VALUE(a.ANSLOGIN)
        IGNORE NULLS
        OVER(
          PARTITION BY UCID
                      ,SEGSTART) ANSLOGIN
     ,FIRST_VALUE(a.DIALED_NUM)
        IGNORE NULLS
        OVER(
          PARTITION BY UCID
                      ,SEGSTART
          ORDER BY
            CASE WHEN LENGTH(DIALED_NUM) > 8 THEN 1 ELSE 0 END ASC
           ,SEGSTOP DESC) DIALEDNUM
     ,LAST_VALUE(a.transferred)
        IGNORE NULLS
        OVER(
          PARTITION BY UCID
                      ,SEGSTART) TRANSFER
     --MULTI ROW WINDOW MATCHES
     ,FIRST_VALUE(CALLID)
      IGNORE NULLS
      OVER(
        PARTITION BY UCID
                    ,SEGSTART
        ORDER BY ((DISPTIME + ANSHOLDTIME + talktime + RINGTIME) / 86400) DESC) CALLID
     ,FIRST_VALUE(a.acd)
      IGNORE NULLS
      OVER(
        PARTITION BY UCID
                    ,SEGSTART
        ORDER BY ((DISPTIME + ANSHOLDTIME + talktime + RINGTIME) / 86400) DESC) ACD
     ,first_VALUE(a.DISSPLIT)
      IGNORE NULLS
      OVER(
        PARTITION BY ucid
                    ,segstart
        ORDER BY ((DISPTIME + ANSHOLDTIME + talktime + RINGTIME) / 86400) DESC) DISSPLIT
     ,FIRST_VALUE(a.cmshost)
      IGNORE NULLS
      OVER(
        PARTITION BY UCID
                    ,SEGSTART
        ORDER BY ((DISPTIME + ANSHOLDTIME + talktime + RINGTIME) / 86400) DESC) CMSHOST
     ,FIRST_VALUE(anslogin)
        OVER(
          PARTITION BY ucid
          ORDER BY segstart ASC NULLS FIRST) COMPLEX_ANSLOGIN
     ,FIRST_VALUE(anslogin)
        IGNORE NULLS
        OVER(
          PARTITION BY ucid
          ORDER BY segstart ASC) COMPLEX_ANSLOGIN_NONULLS
     ,FIRST_VALUE(CALL_DTL_REC_ID)
        OVER(
          PARTITION BY ucid
          ORDER BY segstart ASC NULLS FIRST) COMPLEX_CALL_DTL_REC_ID
     ,ROW_NUMBER()
        OVER(
          PARTITION BY ucid
                      ,CASE
                         WHEN anslogin IS NOT NULL THEN ucid
                         ELSE anslogin
                       END
          ORDER BY segstart ASC) COMPLEX_RN_ANS
     ,first_VALUE(a.ASAIUUI)
        IGNORE NULLS
        OVER(
          PARTITION BY UCID
          ORDER BY CASE WHEN a.asaiuui IS NOT NULL THEN a.segstart END) COMPLEX_ASAIUUI
     ,ROW_NUMBER()
        OVER(
          PARTITION BY ucid
                      ,CASE WHEN origlogin IS NOT NULL THEN origlogin END
          ORDER BY segstart ASC) COMPLEX_RN_ORIG
     ,FIRST_VALUE(a.ORIGLOGIN)
        OVER(
          PARTITION BY UCID
                      ,to_char(
                         segstop
                        ,'DD/MM/YYYY HH24-MI-SS')) COMPLEX_ORIGLOGIN
     ,FIRST_VALUE(a.ORIGLOGIN)
        IGNORE NULLS
        OVER(
          PARTITION BY ucid
                      ,to_char(
                         segstop
                        ,'DD/MM/YYYY HH24-MI-SS')
          ORDER BY segstart ASC) COMPLEX_ORIGLOGIN_NONULLS
     ,FIRST_VALUE(anslogin)
        IGNORE NULLS
        OVER(
          PARTITION BY ucid
                      ,origlogin
          ORDER BY segstart DESC) COMPLEX_ANSLOGIN_ORIG
     ,LAST_VALUE(a.transferred)
        IGNORE NULLS
        OVER(
          PARTITION BY ucid
          ORDER BY segstart ASC) COMPLEX_TRANSFER
     --ASAIUUI WINDOW MATCHES
     ,LAST_VALUE(a.ASAIUUI)
        IGNORE NULLS
        OVER(
          PARTITION BY CALLID
                      ,acd
                      ,CASE
                         WHEN substr(
                                ASAIUUI
                               ,0
                               ,3) = '000' AND
                              asaiuui IS NOT NULL
                         THEN
                           1
                       END
          ORDER BY segstop) ASAIUUI_ASAIUUI
     ,LAST_VALUE(a.ORIGLOGIN)
        IGNORE NULLS
        OVER(
          PARTITION BY CALLID
                      ,SEGSTART
                      ,acd) ASAIUUI_ORIGLOGIN
     ,LAST_VALUE(a.ANSLOGIN)
        IGNORE NULLS
        OVER(
          PARTITION BY CALLID
                      ,SEGSTART
                      ,acd) ASAIUUI_ANSLOGIN
     FROM
     RDHONDT.TEMPAVAYA_PART a
     WHERE
      a.segstart BETWEEN '1-SEP-2019' AND '1-OCT-2019' --ucid = '00002108121561939226'
                                                       AND
      A.dissplit NOT IN (-1) AND
      a.acd IN (1
               ,2
               ,3))
SELECT
 *
FROM
( --SELECT THE PRI MATCH TYPE ***** HIGH QUERY COST... REVISIT
 SELECT /*+ PARALLEL(8) */
  t2.*
 ,row_number()
    OVER(
      PARTITION BY REC_ucid
                  ,rec_login
      ORDER BY
        CASE
          WHEN MATCHTYPE = 'UCID' THEN 1
          WHEN MATCHTYPE = 'UCID_MULTIPARTY' THEN 2
          WHEN MATCHTYPE = 'ASAIUUI' THEN 3
          WHEN MATCHTYPE = 'UCID_OUTBOUND' THEN 4
          WHEN MATCHTYPE = 'ORPHAN_SEGMENT' THEN 5
          WHEN matchtype = 'AM_SEGTIME' THEN 6
        END ASC
       ,transfer DESC) rn
 --UNION ALL THE MATCH TYPES
 FROM
 ( --!!!MATCH TYPE ASAIUU
  SELECT
   O.ucid ORIG_UCID
  ,d.ucid REC_UCID
  ,O.callid ORIG_CALLID
  ,d.callid REC_CALLID
  ,O.callstart ORIG_START
  ,o.callstop ORIG_STOP
  ,D.callstart REC_START
  ,o.callstop REC_STOP
  ,o.segstart ORIG_SEGSTART
  ,o.segstop ORIG_SEGSTOP
  ,d.segstart REC_SEGSTART
  ,d.segstop REC_SEGSTOP
  ,O.ASAIUUI_anslogin ORIG_LOGIN
  ,D.ASAIUUI_anslogin REC_LOGIN
  ,O.dissplit ORIG_SPLIT
  ,O.acd ORIG_ACD
  ,D.DISSPLIT REC_SPLIT
  ,D.acd REC_ACD
  ,D.CMSHOST REC_HOST
  ,O.cmshost ORIG_HOST
  ,D.DIALEDNUM DIALED_NUM
  ,CASE
     WHEN (D.callstop > O.callstop OR
           D.callstop > O.segstop OR
           d.segstop > o.segstop)
     THEN
       1
     ELSE
       0
   END TRANSFER
  ,'ASAIUUI' MATCHTYPE
  FROM
  ucid O
  INNER JOIN ucid D
    ON (D.segstart >= O.CALLSTART AND
        D.segstart <= O.CALLSTOP) AND
       substr(
         d.ASAIUUI_ASAIUUI
        ,-7
        ,7) = o.ASAIUUI_anslogin
  WHERE
   O.ASAIUUI_ANSLOGIN IS NOT NULL AND
   O.ASAIUUI_anslogin <> d.ASAIUUI_anslogin
  --!!!MATCH TYPE MULTIROW
  UNION ALL
  SELECT
   m.UCID
  ,m.REC_UCID
  ,m.ORIG_CALLID
  ,m.REC_CALLID
  ,m.ORIG_START
  ,m.ORIG_STOP
  ,m.REC_START
  ,m.REC_STOP
  ,m.orig_segstart
  ,m.orig_segstop
  ,m.rec_segstart
  ,m.rec_segstop
  ,m.ORIG_LOGIN
  ,m.REC_LOGIN
  ,m.ORIG_SPLIT
  ,m.ORIG_ACD
  ,m.REC_SPLIT
  ,m.REC_ACD
  ,m.REC_HOST
  ,m.ORIG_HOST
  ,m.DIALED_NUM
  ,CASE
     WHEN (m.REC_STOP > m.ORIG_STOP OR
           m.REC_STOP > m.ORIG_SEGSTOP OR
           m.REC_SEGSTOP > m.ORIG_SEGSTOP) OR
          (M.ORIG_SEGSTART = M.REC_SEGSTART AND
           M.ORIG_SEGSTOP = M.REC_SEGSTOP)
     THEN
       1
     ELSE
       0
   END TRANSFER
  ,m.MATCHTYPE
  FROM
  (SELECT /*+ PARALLEL(8) */
    t1.ucid
   ,max(ucid) KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) rec_ucid
   ,max(complex_callid)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) orig_callid
   ,max(complex_callid)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) rec_callid
   ,max(callstart)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_start
   ,max(callstop)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_STOP
   ,max(segstart)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_SEGSTART
   ,max(segstop)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_SEGSTOP
   ,max(callstart)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_START
   ,max(callstop)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_stop
   ,max(segstart)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_segSTART
   ,max(segstop)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_segstop
   ,max(
      CASE
        WHEN ORIG_ROW_MULTITRANSFER = 1
        THEN
          origlogin
        WHEN orig_row = 1
        THEN
          CASE
            WHEN ANSLOGIN IS NOT NULL THEN anslogin
            WHEN origlogin IS NOT NULL THEN origlogin
          END
      END)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1
              THEN
                1
              WHEN orig_row = 1
              THEN
                CASE
                  WHEN ANSLOGIN IS NOT NULL THEN 2
                  WHEN origlogin IS NOT NULL THEN 3
                END
            END) ORIG_LOGIN
   ,max(anslogin)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_login
   ,max(dissplit)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_SPLIT
   ,max(acd)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_ACD
   ,max(dissplit)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_split
   ,max(acd) KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_acd
   ,max(cmshost)
      KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN ans_row = 1 THEN 1 END) REC_host
   ,max(cmshost)
    KEEP (DENSE_RANK FIRST
          ORDER BY
            CASE
              WHEN ORIG_ROW_MULTITRANSFER = 1 THEN 1
              WHEN orig_row = 1 THEN 2
            END) ORIG_HOST
   ,max(dialed_num)
    KEEP (DENSE_RANK FIRST ORDER BY CASE WHEN dial_row = 1 THEN DIALED_NUM END) DIALED_NUM
   ,'UCID_MULTIPARTY' MATCHTYPE
   FROM
   (SELECT /*+ PARALLEL(8) */
     d.ucid
    ,d.SEGSTART
    ,d.SEGSTOP
    ,d.DISSPLIT
    ,d.TRANSFERRED
    ,d.ACD
    ,D.CMSHOST
    ,d.n_ORIGLOGIN origlogin
    ,d.n_ANSLOGIN anslogin
    ,d.DIALED_NUM
    ,d.CALLING_PTY
    ,d.ASAIUUI
    ,d.callstart
    ,d.callstop
    ,d.call_dtl_rec_id test
    ,d.COMPLEX_ASAIUUI
    --if anslogin is blank on first call then select the first call rec in the ucid
    ,CASE
       WHEN (COMPLEX_ANSLOGIN IS NULL AND
             COMPLEX_CALL_DTL_REC_ID = d.call_dtl_rec_id) OR
            n_origlogin = substr(
                            COMPLEX_ASAIUUI
                           ,-7
                           ,7)
       THEN
         1
       ELSE
         CASE
           WHEN COMPLEX_ANSLOGIN IS NOT NULL AND
                n_anslogin IS NOT NULL
           THEN
             COMPLEX_RN_ANS
         END
     END ORIG_ROW
    ,CASE
       WHEN n_origlogin = substr(
                            COMPLEX_ASAIUUI
                           ,-7
                           ,7)
       THEN
         COMPLEX_RN_ORIG
     END ORIG_ROW_MULTITRANSFER
    --first anslogin is blank and row is the first non blank anslogin
    ,CASE
       WHEN COMPLEX_ANSLOGIN IS NULL AND
            n_anslogin = COMPLEX_ANSLOGIN_NONULLS
       THEN
         1
       ELSE
         --no origin login
         CASE
           WHEN n_origlogin IS NULL
           THEN
             --
             CASE
               WHEN n_anslogin IS NOT NULL AND
                    COMPLEX_ANSLOGIN = COMPLEX_ORIGLOGIN
               THEN
                 1
               ELSE
                 CASE
                   WHEN n_anslogin IS NOT NULL AND
                        COMPLEX_ANSLOGIN_nONULLS = n_anslogin AND
                        substr(
                          COMPLEX_ASAIUUI
                         ,-7
                         ,7) = COMPLEX_ORIGLOGIN
                   THEN
                     1
                   ELSE
                     CASE
                       WHEN n_anslogin IS NOT NULL AND
                            (COMPLEX_ANSLOGIN = d.n_origlogin OR
                             COMPLEX_ANSLOGIN = COMPLEX_ORIGLOGIN_NONULLS) AND
                            COMPLEX_ANSLOGIN_ORIG = d.n_ANSLOGIN
                       THEN
                         1
                     END
                 END
             END
           ELSE
             --ORIGLOGIN IS EQUAL TO FIRST ANSLOGIN (DIALED OUT) AND ITS THE FIRST
             CASE
               WHEN n_anslogin IS NOT NULL AND
                    COMPLEX_ANSLOGIN = d.n_origlogin AND
                    COMPLEX_ANSLOGIN = COMPLEX_ORIGLOGIN_NONULLS AND
                    COMPLEX_ANSLOGIN_ORIG = d.n_ANSLOGIN
               THEN
                 1
             END
         END
     END ANS_ROW
    ,CASE
       WHEN COMPLEX_ANSLOGIN IS NULL AND
            d.CALL_DTL_REC_ID = COMPLEX_CALL_DTL_REC_ID
       THEN
         1
       ELSE
         --DIALED OUT AND BY THE SAME LOGIN AS THE ANSROW LOGIN
         CASE
           WHEN n_origlogin = substr(
                                COMPLEX_ASAIUUI
                               ,-7
                               ,7)
           THEN
             1
           ELSE
             CASE
               WHEN n_origlogin IS NOT NULL AND
                    COMPLEX_ANSLOGIN = d.n_origlogin
               THEN
                 COMPLEX_RN_ORIG
             END
         END
     END DIAL_ROW
    ,CASE WHEN COMPLEX_ANSLOGIN IS NULL THEN 1 ELSE COMPLEX_TRANSFER END transfer
    ,COMPLEX_CALLID
    FROM
    ucid d) t1
   GROUP BY
   ucid) m
  --!!!MATCH TYPE UCID
  UNION ALL
  SELECT /*+ PARALLEL(6) */
   O.ucid ORIG_UCID
  ,d.ucid REC_UCID
  ,O.callid ORIG_CALLID
  ,d.callid REC_CALLID
  ,O.callstart ORIG_START
  ,o.callstop ORIG_STOP
  ,D.callstart REC_START
  ,D.callstop REC_STOP
  ,o.segstart ORIG_SEGSTART
  ,o.segstop ORIG_SEGSTOP
  ,d.segstart REC_SEGSTART
  ,d.segstop REC_SEGSTOP
  ,O.anslogin ORIG_LOGIN
  ,D.anslogin REC_LOGIN
  ,O.dissplit ORIG_SPLIT
  ,O.acd ORIG_ACD
  ,D.DISSPLIT REC_SPLIT
  ,D.acd REC_ACD
  ,D.CMSHOST REC_HOST
  ,O.cmshost ORIG_HOST
  ,D.DIALEDNUM DIALED_NUM
  ,CASE
     WHEN (D.callstop > O.callstop OR
           D.callstop > O.segstop OR
           d.segstop > o.segstop)
     THEN
       1
     ELSE
       0
   END TRANSFER
  ,'UCID' MATCHTYPE
  FROM
  ucid D
  INNER JOIN ucid O
    ON (D.SEGSTART >= O.CALLSTART AND
        D.SEGSTART <= O.CALLSTOP + 0.00034722222) AND
       O.anslogin = D.origlogin
  WHERE
   O.ANSLOGIN IS NOT NULL AND
   D.ORIGLOGIN IS NOT NULL AND
   O.anslogin <> d.anslogin AND
   o.anslogin IS NOT NULL
  --!!!MATCH TYPE LOGIN_UNMATCHED

  UNION ALL
  SELECT /*+ PARALLEL(6) */
   O.ucid ORIG_UCID
  ,d.ucid REC_UCID
  ,O.callid ORIG_CALLID
  ,d.callid REC_CALLID
  ,O.callstart ORIG_START
  ,o.callstop ORIG_STOP
  ,D.callstart REC_START
  ,D.callstop REC_STOP
  ,o.segstart ORIG_SEGSTART
  ,o.segstop ORIG_SEGSTOP
  ,d.segstart REC_SEGSTART
  ,d.segstop REC_SEGSTOP
  ,O.ORIGlogin ORIG_LOGIN
  ,D.anslogin REC_LOGIN
  ,O.dissplit ORIG_SPLIT
  ,O.acd ORIG_ACD
  ,D.DISSPLIT REC_SPLIT
  ,D.acd REC_ACD
  ,D.CMSHOST REC_HOST
  ,O.cmshost ORIG_HOST
  ,D.DIALEDNUM DIALED_NUM
  ,CASE
     WHEN (D.callstop > O.callstop OR
           D.callstop > O.segstop OR
           d.segstop > o.segstop)
     THEN
       1
     ELSE
       0
   END TRANSFER
  ,'UCID_OUTBOUND' MATCHTYPE
  FROM
  ucid D
  INNER JOIN ucid O
    ON (D.SEGSTART >= O.CALLSTART AND
        D.SEGSTART <= O.CALLSTOP) AND
       O.ORIGLOGIN = D.origlogin
  WHERE
   O.ANSLOGIN IS NULL AND
   D.ORIGLOGIN IS NOT NULL AND
   O.ORIGLOGIN IS NOT NULL AND
   LENGTH(d.DIALED_NUM) <= 7
  UNION ALL
  SELECT /*+ PARALLEL(6) */
   NULL ORIG_UCID
  ,d.ucid REC_UCID
  ,NULL ORIG_CALLID
  ,d.callid REC_CALLID
  ,NULL ORIG_START
  ,NULL ORIG_STOP
  ,D.callstart REC_START
  ,D.callstop REC_STOP
  ,NULL ORIG_SEGSTART
  ,NULL ORIG_SEGSTOP
  ,d.segstart REC_SEGSTART
  ,d.segstop REC_SEGSTOP
  ,d.origlogin ORIG_LOGIN
  ,d.anslogin REC_LOGIN
  ,-1 ORIG_SPLIT
  ,-1 ORIG_ACD
  ,D.DISSPLIT REC_SPLIT
  ,D.acd REC_ACD
  ,D.CMSHOST REC_HOST
  ,'' ORIG_HOST
  ,D.DIALEDNUM DIALED_NUM
  ,0 TRANSFER
  ,'ORPHAN_SEGMENT' MATCHTYPE
  FROM
  ucid D
  WHERE
   D.ORIGLOGIN IS NOT NULL AND
   D.ANSLOGIN IS NOT NULL
  UNION ALL
  ---test

  SELECT /*+ PARALLEL(6) */
   O.ucid ORIG_UCID
  ,d.ucid REC_UCID
  ,O.callid ORIG_CALLID
  ,d.callid REC_CALLID
  ,O.callstart ORIG_START
  ,o.callstop ORIG_STOP
  ,D.callstart REC_START
  ,d.callstop REC_STOP
  ,o.segstart ORIG_SEGSTART
  ,o.segstop ORIG_SEGSTOP
  ,d.segstart REC_SEGSTART
  ,d.segstop REC_SEGSTOP
  ,O.origlogin ORIG_LOGIN
  ,D.ANSLOGIN REC_LOGIN
  ,O.dissplit ORIG_SPLIT
  ,O.acd ORIG_ACD
  ,D.DISSPLIT REC_SPLIT
  ,D.acd REC_ACD
  ,D.CMSHOST REC_HOST
  ,O.cmshost ORIG_HOST
  ,O.DIALED_NUM DIALED_NUM
  ,CASE
     WHEN (D.callstop > O.callstop OR
           D.callstop > O.segstop OR
           d.segstop > o.segstop)
     THEN
       1
     ELSE
       0
   END TRANSFER
  ,'AM_SEGTIME' MATCHTYPE
  FROM
  ucid d
  INNER JOIN ucid o
    ON --call started no more than 60 seconds after origin
       o.segstart BETWEEN d.SEGSTART - INTERVAL '60' SECOND AND d.SEGSTART AND
       d.segstop BETWEEN o.segstop AND o.segstop + INTERVAL '60' SECOND AND
       --(o.segstop = d.callstop
       ((o.segstop = d.callstop OR
         o.segstop = d.segstop) OR
        (o.callstart BETWEEN d.SEGSTART - INTERVAL '5' SECOND AND d.SEGSTART AND
         d.segstop BETWEEN o.segstop AND o.segstop + INTERVAL '60' SECOND))
  WHERE
   d.dissplit IN (2619
                 ,2618
                 ,2614
                 ,428
                 ,137
                 ,2617
                 ,125
                 ,136
                 ,3067
                 ,127
                 ,2616
                 ,36) AND
   length(o.dialed_num) <= 8 -- the origin call is a dial out
                             AND
   o.origlogin IS NOT NULL AND
   o.anslogin IS NULL --the destination call is answered with an unknown origin
                      AND
   d.anslogin IS NOT NULL AND
   d.origlogin IS NULL AND
   o.split1 = -1 AND
   d.split1 <> -1) t2
 WHERE
  rec_login <> orig_login) t3
WHERE
 rn = 1

计划:

【问题讨论】:

圣洁缺乏缩进蝙蝠侠 我知道这太可怕了 ***.com/help/minimal-reproducible-example "在创建最小示例时,不要为了简洁而牺牲清晰度。使用一致的命名和缩进,并在需要时包含代码 cmets。使用代码编辑器的快捷方式来格式化代码。另外,使用空格而不是选项卡 - 选项卡在 Stack Overflow 上的格式可能不正确。" 本着上述 cmets 的精神,没有人能够帮助您调整那么大而丑陋的东西,而无需至少获得解释计划。我的建议是分而治之。将其分解为更小的查询,并找出对性能影响最大的地方。调整它。继续下一个性能最差的子查询或函数,依此类推。起泡、冲洗、重复。 【参考方案1】:

您在每个选择上都有随机并行提示,这并不总是有助于提高性能,然后是一大堆查询,我宁愿在类似过程的代码中调用它们,然后将它们插入到一些临时表中。

插入表格... 与...选择...; 犯罪; 插入表... 选择 ... ; 犯罪; 等等。

对于内联函数,我会根据某些条件取最小值和最大值。

【讨论】:

以上是关于Oracle 查询性能——多个复杂的窗口函数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用似乎忽略索引的窗口函数提高查询的性能?

定义窗口并在多个分析列中使用它

Oracle 给表加多个字段

这个查询如何使用窗口函数为每个键返回多个结果?

将多个 self JOIN 转换为窗口函数或子查询 (SQL)

无法在 Oracle 的窗口函数中使用 ORDER BY 子句