2016-07-28 123 views
0

我正在將數據從一個表複製到另一個表。在複製時我正在做一些計算來修改一列。如何優化SQL Server查詢

SQL Server查詢:

INSERT INTO rat_proj_duration_map_2 
    SELECT 
    r.*, 
    r.hour_val/(CASE 
     WHEN week_val = 1 AND 
     (SELECT TOP 1 
      hrswk 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE calwk = 2 
     AND r.uid = u.uid 
     AND yr = 2016) 
     > 0 THEN (SELECT TOP 1 
      hrswk 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE calwk = 2 
     AND r.uid = u.uid 
     AND yr = 2016) 
     WHEN (SELECT 
      hrswk 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE r.week_val = us.calwk 
     AND r.uid = u.uid 
     AND yr = 2016) 
     < 1 AND 
     (SELECT 
      MAX(hrswk) 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE r.uid = u.uid 
     AND yr = 2016) 
     > 0 THEN (SELECT 
      MAX(hrswk) 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE r.uid = u.uid 
     AND yr = 2016) 
     WHEN (SELECT 
      COUNT(*) 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE r.uid = u.uid 
     AND yr = 2016) 
     <= 0 THEN 1 
     ELSE (SELECT 
      hrswk 
     FROM UserProfileRATinterface_view us 
     INNER JOIN users u 
      ON u.username = us.username 
     WHERE r.week_val = us.calwk 
     AND r.uid = u.uid 
     AND yr = 2016) 
    END) * 100 AS percentage_val 
    FROM rat_proj_duration_map r 

當我運行此查詢我得到超時問題。

提供的TCP:超時錯誤[258]

SQL Server是不是在我的手,增加超時值。

是否可以優化我的SQL查詢?

+2

附加執行計劃問題:https://www.mssqltips.com/sqlservertip/1856/sql-server-query-execution-plans-in- SQL服務器管理工​​作室/ – Backs

回答

0

您的case子句中的子查詢看起來基本相同。您可以通過定義此子查詢的分組版本(... where yr=2016 group by u.uid)(最好將其作爲公用表表達式)來簡化整個命令,然後使用該命令。這可能會節省大量冗餘操作。

下可能工作(沒有測試過):

;WITH usrall as (
SELECT u.uid ui, hrswk hw, r.week wk, us.calwk cw 
FROM UserProfileRATinterface_view us 
INNER JOIN users u on u.username=us.username 
WHERE r.uid=u.uid and yr=2016 
), usrgrp as (
SELECT ui gui, MAX(hrswk) ghw, count(*) gcnt FROM usrall group by ui 
), denom as (
SELECT gui dui, COALESCE(MAX(w2.hw), MAX(wkwc.hw), MAX(gwh)) dnm 
FROM usrgrp 
LEFT JOIN usrall w2 ON w2.ui=gui AND w2.cw=2 AND w2.hw>0 
LEFT JOIN usrall wkcw ON wkcw.ui=gui AND wkcw.wk=wkcw.cw AND wkwc.hw<1 
GROUP BY gui 
)   
SELECT r.*, r.hour_val/d.dnm 
FROM rat_proj_duration_map r 
INNER JOIN denom d ON d.dui=u.uid 

基本上我已經試過(我希望它的工作原理: - /)取代的情況下由COALESCE()功能檢查三種可能計算的構建一個接一個地值。第一個非空值被接受。

正如我所說:我沒有測試過它。祝你好運

0

你確定這個查詢在邏輯上是正確的嗎?你有幾個TOP 1 s沒有具體ORDER BY,子標記比較沒有TOP子選擇(我假設,如果您在其他子查詢中使用top具有相同的來源,可能會返回多個行)。

是的 - 這個查詢可以優化。你可以得到你需要一個子查詢語句中的所有值,避免同一子查詢的多個執行的rat_proj_duration_map的每一行,你現在有:

INSERT INTO rat_proj_duration_map_2 
    SELECT 
     r.*, 
     r.hour_val/(CASE 
           WHEN week_val = 1 AND us.min_hrswk_2 > 0 
           THEN us.min_hrswk_2 
           WHEN us.min_hrswk_week_val <1 
           AND max_hrswk > 0 
           THEN max_hrswk 
           WHEN us.cnt <= 0 
           THEN 1 
           ELSE min_hrswk_week_val 
          END) * 100 as percentage_val 
    FROM 
     rat_proj_duration_map r 
    OUTER APPLY 
    (
     SELECT 
      count(*) as cnt, 
      MIN(CASE WHEN calcw = 2 THEN hrswk END) as min_hrswk_2, 
      MIN(CASE WHEN calcw = r.week_val THEN hrswk END) as min_hrswk_week_val, 
      MAX(hrswk) as max_hrswk 
     FROM UserProfileRATinterface_view us 
     inner join users u on u.username=us.username 
     WHERE r.uid=u.uid and yr=2016 
    ) us 

但我不能肯定,如果原來的邏輯是正確的。而這種情況下,我的想法是這樣的:

... 
    r.hour_val/COALESCE(NULLIF(us.min_hrswk_2, 0), 
     NULLIF(us.min_hrswk_week_val, 0), NULLIF(max_hrswk, 0), 1) 
...