簡體   English   中英

查詢優化-UNION

[英]Query Optimisation - UNION

我使用以下查詢從3個表SOURCE1,SOURCE2,SOURCE3中獲取數據,這些數據需要插入到另一個表FINAL中。我想知道是否可以進一步優化以下查詢。

SELECT s3.unit ,s2.col1,s2.col2, '00-1' dest  
FROM source1 s1   
INNER JOIN source2 s2 ON s1.altunit = s2.unit  
INNER JOIN source3 s3 ON s1.unit = s3.unit   
WHERE sysdate BETWEEN s1.e_date AND  s1.d_date   
AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1)  

UNION  

SELECT s3.price,s2.col1,s2.col2, '00-1' dest  
FROM source1 s1   
INNER JOIN source2 s2 ON s1.altunit = s2.unit  
INNER JOIN source3 s3 ON s1.unit = s3.unit   
WHERE sysdate BETWEEN s1.e_date AND  s1.d_date   
AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1) 

UNION  

SELECT s3.price,s2.col1,s2.col2, s2.dest  
FROM source1 s1   
INNER JOIN source2 s2 ON s1.altunit = s2.unit  
INNER JOIN source3 s3 ON s1.unit = s3.unit   
WHERE sysdate BETWEEN s1.e_date AND  s1.d_date   
AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1)  

UNION

SELECT s3.cost,s2.col1,s2.col2, s2.dest  
FROM source1 s1   
INNER JOIN source2 s2 ON s1.altunit = s2.unit  
INNER JOIN source3 s3 ON s1.unit = s3.unit   
WHERE sysdate BETWEEN s1.e_date AND  s1.d_date   
AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1) 

僅SELECT語句的第1個位置的數據變化。 其余條件-JOIN和WHERE子句保持不變。 我們只需要為選擇的每1行發出4行:

SELECT variants.*
FROM source1 s1
INNER JOIN source2 s2 ON s1.altunit = s2.unit
INNER JOIN source3 s3 ON s1.unit = s3.unit
CROSS APPLY (
    SELECT s3.unit ,s2.col1,s2.col2, '00-1' dest UNION
    SELECT s3.price,s2.col1,s2.col2, '00-1' dest UNION
    SELECT s3.price,s2.col1,s2.col2, s2.dest UNION
    SELECT s3.cost,s2.col1,s2.col2, s2.dest
) variants
WHERE sysdate BETWEEN s1.e_date AND s1.d_date
AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1)

Google告訴我Oracle 10支持CTE,如果確實如此,您可以這樣做:

with tmp (unit, price, cost, col1, col2, dest1, dest2) as (
    SELECT s3.unit, s3.price, s3.cost, s2.col1, s2.col2, s2.dest, '00-1'  
    FROM source1 s1   
    JOIN source2 s2 
        ON s1.altunit = s2.unit  
    JOIN source3 s3 
        ON s1.unit = s3.unit   
    WHERE sysdate BETWEEN s1.e_date AND  s1.d_date   
      AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1)
)
select unit, col1, col2, dest2 from tmp  
union
select price, col1, col2, dest2 from tmp    
union
select price, col1, col2, dest1 from tmp  
union
select cost, col1, col2, dest1 from tmp    

我假設Oracle將以比原始查詢更有效的方式對其進行評估。

如果我正確地閱讀了此內容,則除了select之外,所有四個子查詢都相同。 通常,最快的方法是使用cross join和條件邏輯取消數據透視:

SELECT (case when n.n = 1 then s3.unit
             when n.n in (2, 3) then s3.price
             when n.n = 4 then s3.cost
        end) as unit,
       s2.col1, s2.col2,
       (case when n.n in (1, 2) then '00-1'
             when n.n in (3, 4) then s2.dest
        end) as dest  
FROM source1 s1 INNER JOIN
     source2 s2
     ON s1.altunit = s2.unit INNER JOIN
     source3 s3
     ON s1.unit = s3.unit CROSS JOIN
     (select 1 as n from dual union all select 2 from dual union all select 3 from dual union all select 4 from dual
     ) n 
WHERE sysdate BETWEEN s1.e_date AND  s1.d_date   
AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1);

如果您仍需要消除重復項,請使用select distinct

就像@usr所建議的那樣, CROSS APPLY是做到這一點的方法。 我只想添加AND s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1)可以成為性能殺手。 這取決於您可以擁有多少個不同的“單位”:

  • 如果SELECT unit FROM source1 WHERE u_sw = 1返回4個值,則保持該值不變。
  • 如果返回的值超過40個,則只需使用INNER JOIN

原版的 :

FROM source1 s1   
    [...]
WHERE
    s1.unit IN (SELECT unit FROM source1 WHERE u_sw = 1)

至 :

FROM source1 s1   
    INNER JOIN source1 s1limit 
        ON s1limit.unit = s1.unit 
        AND s1limit.u_sw = 1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM