如何优化左连接子句中含有 or 的查询?

问题描述 投票:0回答:2

当我执行我的代码时,它花费了很多小时并且还没有完成。我知道问题是在左连接子句中使用“or”。所以我想知道如何重写这段可以执行的代码。

SELECT  WFTD.RELA
            , WFTCS.PARENT_TASK AS CONSULT_TASK_ID
            , WFTCS.CREATE_DATE AS CONSULT_DATE
            , WFTD_THIS_TASK.APPROVED_RESULT_DATE AS THISTASK_APPROVED_RESULT_DATE
FROM TNH_WF WF
INNER JOIN TND_WF_TASK WFT ON WFT.WF_ID = WF.WF_ID AND WFT.OWNER_ATONEMENT IS NOT NULL AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06', 'N07')
INNER JOIN TND_WF_TASK WFTCS ON WFTCS.WF_ID = WFT.WF_ID AND WFTCS.WORK_TRAY_ID = 'N07' 

LEFT JOIN TND_WF_TASK_DETAIL WFTD_THIS_TASK ON WFTD_THIS_TASK.WF_TASK_ID = WFT.WF_TASK_ID AND WFTD_THIS_TASK.POL_COV_FLAG = 'P'

LEFT JOIN TND_WF_TASK_DETAIL WFTD

ON (
            (
                (WFTD.WF_TASK_ID = WFT.PARENT_TASK 
                AND WFT.WORK_TRAY_ID IN ('N07') 
                AND WFTD.CONSIDER_RESULT_CODE LIKE '%Consult%') 
            
            OR 
                (WFTD.NEXT_TASK_ID = WFT.WF_TASK_ID 
                AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06')) 
            AND 
                WFT.STATUS IN (0,1,2)
            )
        
        OR 
        (WFTD.WF_TASK_ID = WFT.WF_TASK_ID 
        AND WFT.STATUS IN (3)))
    
    AND WFTD.POL_COV_FLAG = 'P'
sql oracle query-optimization
2个回答
0
投票
in this optimized query i did following things:

 1. I've separated the JOIN conditions into separate LEFT JOIN clauses
    to improve readability.
 2. I've simplified the WHERE clause by using an explicit check for
    WFTD.WF_TASK_ID IS NOT NULL OR WFT.STATUS = 3 instead of the complex
    condition in the original query.
 3. Make sure proper indexing is in place for the join columns and the
    columns used in WHERE conditions for optimal performance.

    SELECT  
    WFTD.RELA,
    WFTCS.PARENT_TASK AS CONSULT_TASK_ID,
    WFTCS.CREATE_DATE AS CONSULT_DATE,
    WFTD_THIS_TASK.APPROVED_RESULT_DATE AS THISTASK_APPROVED_RESULT_DATE
FROM 
    TNH_WF WF
INNER JOIN 
    TND_WF_TASK WFT ON WFT.WF_ID = WF.WF_ID 
        AND WFT.OWNER_ATONEMENT IS NOT NULL 
        AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06', 'N07')
INNER JOIN 
    TND_WF_TASK WFTCS ON WFTCS.WF_ID = WFT.WF_ID 
        AND WFTCS.WORK_TRAY_ID = 'N07' 
LEFT JOIN 
    TND_WF_TASK_DETAIL WFTD_THIS_TASK ON WFTD_THIS_TASK.WF_TASK_ID = WFT.WF_TASK_ID 
        AND WFTD_THIS_TASK.POL_COV_FLAG = 'P'
LEFT JOIN 
    TND_WF_TASK_DETAIL WFTD ON WFTD.WF_TASK_ID = WFT.PARENT_TASK 
        AND WFT.WORK_TRAY_ID IN ('N07') 
        AND WFTD.CONSIDER_RESULT_CODE LIKE '%Consult%'
        AND WFT.STATUS IN (0, 1, 2)
        AND WFTD.POL_COV_FLAG = 'P'

LEFT JOIN 
    TND_WF_TASK_DETAIL WFTD_NEXT ON WFTD_NEXT.NEXT_TASK_ID = WFT.WF_TASK_ID 
        AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06') 
        AND WFT.STATUS IN (0, 1, 2)
        AND WFTD_NEXT.POL_COV_FLAG = 'P'
WHERE 
    (WFTD.WF_TASK_ID IS NOT NULL OR WFT.STATUS = 3)

0
投票

虽然我们在没有看到您的执行数据的情况下无法确定,但这很可能是由于您加入了

WFTD
,正如您所猜对的那样。有多种方法可以解决这个问题。从最少的重写到最大的重写:

  1. 向查询块添加

    /*+ USE_CONCAT */
    提示(位于顶部
    SELECT
    关键字之后)。这可能会促使 Oracle 将您的查询重写为一系列
    UNION
    (或
    UNION ALL
    后跟
    DISTINCT
    排序)块,每个块都有明确的等值连接条件以消除
    OR
    条件。但由于您还有一些复合和
    IN
    运算符,Oracle 可能会遇到困难。值得一试,因为除了提示之外不需要更改代码。

  2. 如果

    WFTD
    的连接是1:1连接(
    WFTD
    中最多只有一行可能匹配任何可能的连接条件),您可以简单地连接到表3次并然后从找到的结果中取出您需要的列:

           SELECT  COALESCE(WFTD1.RELA,WFTD2.RELA,WFTD3.RELA) AS RELA
                       , WFTCS.PARENT_TASK AS CONSULT_TASK_ID
                       , WFTCS.CREATE_DATE AS CONSULT_DATE
                       , WFTD_THIS_TASK.APPROVED_RESULT_DATE AS THISTASK_APPROVED_RESULT_DATE
           FROM TNH_WF WF
           INNER JOIN TND_WF_TASK WFT ON WFT.WF_ID = WF.WF_ID AND WFT.OWNER_ATONEMENT IS NOT NULL AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06', 'N07')
           INNER JOIN TND_WF_TASK WFTCS ON WFTCS.WF_ID = WFT.WF_ID AND WFTCS.WORK_TRAY_ID = 'N07' 
    
           LEFT JOIN TND_WF_TASK_DETAIL WFTD_THIS_TASK ON WFTD_THIS_TASK.WF_TASK_ID = WFT.WF_TASK_ID AND WFTD_THIS_TASK.POL_COV_FLAG = 'P'
    
           LEFT JOIN TND_WF_TASK_DETAIL WFTD1 ON WFTD1.WF_TASK_ID = WFT.PARENT_TASK 
                                             AND WFTD1.CONSIDER_RESULT_CODE LIKE '%Consult%'
                                             AND WFT.WORK_TRAY_ID IN ('N07') 
                                             AND WFT.STATUS IN (0,1,2)
                                             AND WFTD1.POL_COV_FLAG = 'P'
    
           LEFT JOIN TND_WF_TASK_DETAIL WFTD2 ON WFTD2.NEXT_TASK_ID = WFT.WF_TASK_ID 
                                             AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06')
                                             AND WFT.STATUS IN (0,1,2)
                                             AND WFTD2.POL_COV_FLAG = 'P'
    
           LEFT JOIN TND_WF_TASK_DETAIL WFTD3 ON WFTD3.WF_TASK_ID = WFT.WF_TASK_ID 
                                             AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06')
                                             AND WFT.STATUS IN (3)       
                                             AND WFTD3.POL_COV_FLAG = 'P'
    
  3. 最后,如果 Oracle 无法通过提示为您重写它,并且与 WFTD 的连接可能not 为 1:1(这可能导致上面选项 #2 中的行扩展 [行数过多]),那么您可以使用

    UNION
    重写整个查询。将其复制粘贴三次,并用
    UNION
    连接,将连接折叠为每个连接中的三个连接之一:

         SELECT  WFTD.RELA
                     , WFTCS.PARENT_TASK AS CONSULT_TASK_ID
                     , WFTCS.CREATE_DATE AS CONSULT_DATE
                     , WFTD_THIS_TASK.APPROVED_RESULT_DATE AS THISTASK_APPROVED_RESULT_DATE
         FROM TNH_WF WF
         INNER JOIN TND_WF_TASK WFT ON WFT.WF_ID = WF.WF_ID AND WFT.OWNER_ATONEMENT IS NOT NULL AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06', 'N07')
         INNER JOIN TND_WF_TASK WFTCS ON WFTCS.WF_ID = WFT.WF_ID AND WFTCS.WORK_TRAY_ID = 'N07' 
    
         LEFT JOIN TND_WF_TASK_DETAIL WFTD_THIS_TASK ON WFTD_THIS_TASK.WF_TASK_ID = WFT.WF_TASK_ID AND WFTD_THIS_TASK.POL_COV_FLAG = 'P'
    
         LEFT JOIN TND_WF_TASK_DETAIL WFTD ON WFTD.WF_TASK_ID = WFT.PARENT_TASK 
                                         AND WFTD.CONSIDER_RESULT_CODE LIKE '%Consult%'
                                         AND WFT.WORK_TRAY_ID IN ('N07') 
                                         AND WFT.STATUS IN (0,1,2)
                                         AND WFTD.POL_COV_FLAG = 'P'
         UNION
         SELECT  WFTD.RELA
                     , WFTCS.PARENT_TASK AS CONSULT_TASK_ID
                     , WFTCS.CREATE_DATE AS CONSULT_DATE
                     , WFTD_THIS_TASK.APPROVED_RESULT_DATE AS THISTASK_APPROVED_RESULT_DATE
         FROM TNH_WF WF
         INNER JOIN TND_WF_TASK WFT ON WFT.WF_ID = WF.WF_ID AND WFT.OWNER_ATONEMENT IS NOT NULL AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06', 'N07')
         INNER JOIN TND_WF_TASK WFTCS ON WFTCS.WF_ID = WFT.WF_ID AND WFTCS.WORK_TRAY_ID = 'N07' 
    
         LEFT JOIN TND_WF_TASK_DETAIL WFTD_THIS_TASK ON WFTD_THIS_TASK.WF_TASK_ID = WFT.WF_TASK_ID AND WFTD_THIS_TASK.POL_COV_FLAG = 'P'
    
         LEFT JOIN TND_WF_TASK_DETAIL WFTD  ON WFTD.NEXT_TASK_ID = WFT.WF_TASK_ID 
                                           AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06')
                                           AND WFT.STATUS IN (0,1,2)
                                           AND WFTD.POL_COV_FLAG = 'P'
         UNION
         SELECT  WFTD.RELA
                     , WFTCS.PARENT_TASK AS CONSULT_TASK_ID
                     , WFTCS.CREATE_DATE AS CONSULT_DATE
                     , WFTD_THIS_TASK.APPROVED_RESULT_DATE AS THISTASK_APPROVED_RESULT_DATE
         FROM TNH_WF WF
         INNER JOIN TND_WF_TASK WFT ON WFT.WF_ID = WF.WF_ID AND WFT.OWNER_ATONEMENT IS NOT NULL AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06', 'N07')
         INNER JOIN TND_WF_TASK WFTCS ON WFTCS.WF_ID = WFT.WF_ID AND WFTCS.WORK_TRAY_ID = 'N07' 
    
         LEFT JOIN TND_WF_TASK_DETAIL WFTD_THIS_TASK ON WFTD_THIS_TASK.WF_TASK_ID = WFT.WF_TASK_ID AND WFTD_THIS_TASK.POL_COV_FLAG = 'P'
    
         LEFT JOIN TND_WF_TASK_DETAIL WFTD ON WFTD.WF_TASK_ID = WFT.WF_TASK_ID 
                                           AND WFT.WORK_TRAY_ID IN ('N02', 'N03', 'N06')
                                           AND WFT.STATUS IN (3)       
                                           AND WFTD.POL_COV_FLAG = 'P'
    
© www.soinside.com 2019 - 2024. All rights reserved.