0

我有一個存儲過程,它通過UNION ALL組合來自多個表的數據。如果傳遞到存儲過程的參數不適用於特定的表,我試圖通過使用「幫助位」來「短路」該表。 @DataSomeTableExists並在WHERE子句中添加相應的條件,例如,Awkward JOIN導致性能不佳

存儲過程中的一個(psuedo)表有點尷尬,給我帶來一些悲傷。

DECLARE @DataSomeTableExists BIT = (SELECT CASE WHEN EXISTS(SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') THEN 1 ELSE 0 END); 
... 

UNION ALL 

SELECT * 
FROM REF_MinuteDimension AS dim WITH (NOLOCK) 
CROSS JOIN (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') AS T  
CROSS APPLY dbo.fGetLastValueFromSomeTable(T.ParentId, dim.TimeStamp) dpp 
WHERE @DataSomeTableExists = 1 AND dim.TimeStamp >= @StartDateTime AND dim.TimeStamp <= @EndDateTime 

UNION ALL 

... 

注:REF_MinuteDimension無非是用分鐘爲增量smalldatetimes更多。

(1)執行計劃(下圖)表示對嵌套循環運算符的警告,表示不存在連接謂詞。這可能不是很好,但表格之間確實沒有自然連接。有沒有更好的方法來編寫這樣的查詢?對於T中的每個ParentId,我希望@StartDateTime和@EndDateTime之間的每分鐘UDF的值。

(2)即使當@DataSomeTableExists = 0時,在該查詢中的表上存在由SET STATISTICS IO ON報告的表的I/O活動和實際執行計劃。執行計劃報告14.2%的成本,考慮到這些表格甚至不適用於這種情況。

SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable'重新排空。

這是我寫查詢的方式嗎?爲什麼幫助器位或空的T短路這個查詢?

enter image description here

+0

你應該改變'DECLARE'的事情是:'聲明@DataSomeTableExists位= 0 如果存在(SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') begin \t set @DataSomeTableExists = 1 end'。這很難讀,所以這裏是[pastebin](http://pastebin.com/4y0VTJCD)。那麼爲什麼'CROSS JOIN'查詢中還沒有「短路」'WHERE'參數呢?我應該提到,如果這樣做能夠奏效,我就不知道了,因爲寫一個sproc是一種奇怪的方式。 –

回答

0

對於2)我可以肯定地說,行

CROSS JOIN (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable') AS T 

生病力#T進行分析和輸入連接。你可以創建一個帶有和沒有連接的SP版本,並使用該標誌來執行一個或另一個,但是我不能說存在任何響應時間|| cpu clock || I/O帶寬||內存。

對於1)如果您使用的是SQL Server 2005或更高版本,並且密切關注該UDF,建議刪除(nolock)。沒有一個好的SQL小提琴就不能說更多。

0

我應該提,我有不知道如果這都不會工作,因爲它是一種寫一個存儲過程和表值的UDF不能很好的查詢優化器瞭解一種奇怪的方式。您可能必須根據IF語句有條件地將結果集構建到表變量或臨時表中,然後返回該數據。但我會嘗試這一點,首先:

--helper bit declared 
declare @DataSomeTableExists BIT = 0x0 
if exists (select 1 from #T where StorageTable = 'DATA_SomeTable') 
begin 
    set @DataSomeTableExists = 0x1 
end 

... 

UNION ALL 

SELECT * 
FROM REF_MinuteDimension AS dim WITH (NOLOCK) 
CROSS JOIN (SELECT * FROM #T WHERE StorageTable = 'DATA_SomeTable' and @DataSomeTableExists = 0x1) AS T 
CROSS APPLY dbo.fGetLastValueFromSomeTable(T.ParentId, dim.TimeStamp) dpp 
WHERE @DataSomeTableExists = 0x1 AND dim.TimeStamp >= @StartDateTime AND dim.TimeStamp <= @EndDateTime 

UNION ALL 

... 

如果你還不知道,這個UDF可能是給你在執行計劃怪異的讀數。我不知道給你提供準確的數據,但你應該四處搜尋以瞭解限制。

+0

感謝您的回覆。這似乎是訣竅。好奇你爲什麼改變了幫助位聲明?這僅僅是爲了可讀性嗎? –

+0

是的。您聲明瞭一個變量,將其設置爲默認值,同時還使用具有子查詢SELECT的'EXISTS'查詢。對於下一位開發人員來說,如果有其他方法可以輕鬆編寫,那麼這對於坐下來閱讀很有幫助。 –

-1

由於您的查詢取決於運行時變量,因此請考慮使用動態SQL來即時創建查詢。這樣你可以包含你想要的表格並排除你不想要的表格。

也有不利動態SQL,所以read up

+0

作爲@jean的建議,更好的選擇是創建一個存儲過程,分別用於何時需要提取數據以及何時不提供數據。然後,從主精靈,有條件地發射一個或其他的一個。然後,你正在使用*動態邏輯*(並保留查詢計劃),而不是*動態SQL *(這幾乎從來沒有真正需要,所以應該避免)。 –