2012-03-08 24 views
2

我有一個類似this MySQL question的案例,涉及IN子句,但是用於SQL Server。SQL服務器和一個IN子句中的大範圍值的效率

具體來說,我正在構建一個可執行的SQL字符串,並且在其中有一個很長的枚舉項目列表,用於在IN子句(I.E. 1000+)中使用。

這是一種從動態條件列表構造過濾器的有效方式,還是應該將條件數據插入臨時表中,然後將其導入我的導出表以進行過濾操作?

如果答案不是非常簡單,每種方法的優點和缺點將不勝感激。

如果有人問這個問題,我表示歉意。鏈接的MySQL問題相當老舊。我想象這是對SQL Server的重複,但我找不到它。

回答

2

您忘記告訴我們您正在使用的SQL Server版本。當然,每個新版本都有能力幫助我們以更高效的方式解決問題。

在SQL Server 2005 +,你可以用一個簡單的表值函數這樣來實現連接:

CREATE FUNCTION [dbo].[SplitInts] 
(
    @List  VARCHAR(MAX), 
    @Delimiter CHAR(1) 
) 
RETURNS TABLE 
AS 
    RETURN (SELECT Item FROM (SELECT Item = x.i.value('(./text())[1]', 'int') FROM 
      (SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>') 
       + '</i>').query('.')) AS a CROSS APPLY [XML].nodes('i') AS x(i) 
     ) AS y WHERE Item IS NOT NULL 
    ); 
GO 

現在傳遞到自己的大名單,並加入:

CREATE PROCEDURE dbo.GetData 
    @List VARCHAR(MAX) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT t.col1, t.col2 --, ... 
     FROM dbo.DataTable AS t 
     INNER JOIN dbo.SplitInts(@List, ',') AS i 
     ON t.ColumnID = i.Item; 
END 
GO 

這是不是太棒了(我blogged about performance of various methods here和5000以下的值幾乎沒有什麼區別),但可能會更好地執行更好的查詢特設IN (...huge list...)

在SQL Server 2008+中,您可以使用表值參數。與上面類似,您可以將DataTable或C#中的任何結構傳遞給存儲過程並執行聯接。如果您使用的是2008或更高版本,我也可以添加一個示例。

+0

啊,優秀的文章,這正是我所期待的。在閱讀您的文章後,我必須說,500-1000項目測試的XML打嗝很奇怪。你有沒有發現這種低效率的原因?只是好奇。 – RLH 2012-03-08 19:29:35

+0

不,我一直有意味着再次測試(並且在比較中包括TVP),但還沒有出現。 – 2012-03-08 19:31:07

1

我建議使用臨時表方法,並使用where exists(...)子句,例如,

select * from Employees e 
where exists(select 1 from BigEmplCriteriaTable where criteria=e.EmployeeLoc)