2013-02-22 64 views
0

我有一個存儲過程最近一直有一些問題,我最終縮小到1 SELECT。問題是我無法弄清楚究竟發生了什麼事情來殺死這個查詢的性能。我重寫了它,但我不確定重寫是否是完全相同的數據。SELECT(SUBQUERY)奇怪的性能問題

原始查詢:

SELECT 
    @userId, p.job, p.charge_code, p.code 
, (SELECT SUM(b.total) FROM dbo.[backorder w/total] b WHERE b.ponumber = p.ponumber AND b.code = p.code) 
, ISNULL(jm.markup, 0) 
, (SELECT SUM(b.TOTAL_TAX) FROM dbo.[backorder w/total] b WHERE b.ponumber = p.ponumber AND b.code = p.code) 
, p.ponumber 
, p.billable 
, p.[date] 
FROM dbo.PO p 
INNER JOIN dbo.JobCostFilter jcf 
    ON p.job = jcf.jobno AND p.charge_code = jcf.chargecode AND jcf.userno = @userId 
LEFT JOIN dbo.JobMarkup jm 
    ON jm.jobno = p.job 
    AND jm.code = p.code 
LEFT JOIN dbo.[Working Codes] wc 
    ON p.code = wc.code 
INNER JOIN dbo.JOBFILE j 
    ON j.JOB_NO = p.job 
WHERE (wc.brcode <> 4 OR @BmtDb = 0) 
GROUP BY p.job, p.charge_code, p.code, p.ponumber, p.billable, p.[date], jm.markup, wc.brcode 

這個查詢將幾乎永遠不會結束運行。它實際上超時了我們有一些更大的工作。

如果我更改選擇的2子查詢念想,而不是加入:

SELECT 
    @userid, p.job, p.charge_code, p.code 
    , (SELECT SUM(b.TOTAL)) 
    , ISNULL(jm.markup, 0) 
    , (SELECT SUM(b.TOTAL_TAX)) 
    , p.ponumber, p.billable, p.[date] 
FROM dbo.PO p 
INNER JOIN dbo.JobCostFilter jcf 
    ON p.job = jcf.jobno AND p.charge_code = jcf.chargecode AND jcf.userno = 11190030 
INNER JOIN [BACKORDER W/TOTAL] b 
    ON P.PONUMBER = b.ponumber AND P.code = b.code 
LEFT JOIN dbo.JobMarkup jm 
    ON jm.jobno = p.job 
    AND jm.code = p.code 
LEFT JOIN dbo.[Working Codes] wc 
    ON p.code = wc.code 
INNER JOIN dbo.JOBFILE j 
    ON j.JOB_NO = p.job 
WHERE (wc.brcode <> 4 OR @BmtDb = 0) 
GROUP BY p.job, p.charge_code, p.code, p.ponumber, p.billable, p.[date], jm.markup, wc.brcode 

的數據找出來非常幾乎完全相同我(雖然有成千上萬行的整體,所以我可能是錯的),並且運行速度非常快。

理解任何想法..

+0

你的問題是什麼?性能由查詢優化器確定。在一個案例中,它比另一個案例做得更好。 – 2013-02-22 22:15:16

+0

查看每個版本的查詢計劃。 – 2013-02-22 22:17:45

+0

您是否嘗試將子查詢拉入CTE?我們在聚合子查詢中遇到了很多性能問題,這些問題通過使用像這樣的聚合的CTE已經大大減輕了。 – 2013-02-22 22:18:26

回答

2
  • 服務表現

在你有少邏輯的第二查詢讀因爲表[延期交貨W/TOTAL]已經被掃描一次。在第一個查詢中,兩個獨立的子查詢是獨立處理的,並且該表被掃描兩次,儘管兩個子查詢都具有相同的謂詞。

  • 正確性

如果要檢查兩個查詢返回你可以使用EXCEPT運算符相同的結果集:

如果同時聲明:

先選擇查詢... EXCEPT 第二個SELECT查詢...

二SELECT查詢.. EXCEPT 先選擇查詢...

返回一個空集的結果集是相同的。

+0

謝謝,我對EXCEPT不熟悉,但我確定它將幫助我診斷任何差異。 – 2013-02-24 16:16:52

1

在正確的方面,你是inner join在第二個查詢荷蘭國際集團[BACKORDER W/TOTAL],所以如果第一個查詢在子查詢Null值,這些行會在第二個查詢丟失。

對於性能而言,優化器是一種啓發式算法 - 它有時會使用非常糟糕的查詢計劃,甚至最小的更改有時也會導致完全不同的查詢計劃。您最好的機會是比較查詢計劃並查看導致差異的原因。