2010-05-11 66 views
2

我在我的數據庫中使用了許多動態查詢過程,因爲我的過濾器沒有修復,所以我採用了@filter作爲參數並在過程中傳遞。在Sqlserver 2005中動態查詢的缺點?

Declare @query as varchar(8000) 
Declare @Filter as varchar(1000) 

set @query = 'Select * from Person.Address where 1=1 and ' + @Filter 

exec(@query) 

就像我的過濾器包含表中的任何字段進行比較。

這會影響我的表現嗎? 是否有任何替代方法來實現這種類型的東西

+0

我們在我們的項目中有複雜的查詢,這需要「WHERE」子句中的很多參數。我們的dba傾向於對這些情況進行動態查詢,但我對此並不滿意。恕我直言,只要需要採取措施防範參數嗅探,靜態查詢應該更快。有沒有人對KuldipMCA的問題有很好的回答,這樣我可以讓我們的高級DBA停止支持動態查詢? – Cagdas 2010-05-11 07:41:10

回答

0

只要沒有其他聯接必須動態地檢查參數的值可能很重要,並且唯一的動態部分是WHERE子句,這可能會以及具有所有可能參數的靜態查詢。所以你有以下情況:

如果你想檢查一切可能的值(負數/零/零/正/空字符串/等),需要使用輔助參數,如@ signifficant_param1 ,以及@ param1的原始值。

[...] 
WHERE 
    (@signifficant_param1=0 or (@param1 is null and field1 is null) or @param1=field1) 
    AND (@signifficant_param2=0 or (@param2 is null and field2 is null) or @param2=field2) 
    //etc 
[...] 

這是我能想象到的最普遍的條款。 基本上它會驗證@signifficant_param的值。如果應該考慮這個參數,它將是1,條件的第一部分將是錯誤的,並且第二部分(參數的驗證)將會發生。在第二階段,如果@param爲空,那麼您正在查找所有空值field,並且您無法將null與null比較,因爲它們不相等。然後發生常規非空值匹配的驗證。

如果,另一方面,在field值不能爲空,或者不能爲負數,您不需要@signifficant_param,因爲你可以做一個規則,例如,如果@param爲null ,那麼這個值是不是signifficant(前面的情況,你會搜索所有空值代替),你可以使用以下命令:

[...] 
WHERE 
    field1=case when @param1 is null then field1 else @param1 end --first way with case statement 
    and (@param2 is null or [email protected]) --second way with boolean logic 
[...] 
+1

你必須非常小心這個構造。是的,這幾乎是通用的WHERE子句,但它不像他們所說的那樣是SARGable。也就是說,它不能有效地使用你的索引來處理你的WHERE條件。這對篩選數據的小型子集很好,但對於大型表的搜索,這將導致數據庫優化器進行掃描。 – 2010-05-11 09:10:37

+0

不錯的回答和很好的評論,但我同意戴夫馬克,這是不是有效的方式來解決這個問題。 – KuldipMCA 2010-05-11 09:28:08

+0

是的,這是部分正確的,但是當從MSSQL內部構建動態查詢時,不能存儲大於8000個字符的查詢。根據我的經驗,這是完全正確的,因爲我在大型表(數以億計的記錄)上使用了這樣的算法,因爲表沒有在需要的字段上編制索引。一旦在另一臺服務器上建立了複製,我就可以運行數據庫引擎優化顧問,它提出了複雜的索引和統計數據,之後性能提高了〜10。 我說試試不傷害。 – AlexanderMP 2010-05-11 12:30:48

0

真的是沒有錯的動態查詢,本身。但是你打算這麼做的方式是可怕的。這意味着你的參數將成爲@Filter的一部分,它只是要求SQL注入攻擊。這也意味着您的查詢計劃不可能被重用,由於過量的查詢重新編譯會導致高CPU和低吞吐量。

您需要確保您生成的動態SQL已正確參數化。您還需要確保在使用ADO.NET代碼(或者您可能使用的任何數據訪問技術)訪問它時,您使用SqlParameter(或等價物)對象。

2

爲了提高性能,只有在數據庫可以重複使用現有計劃的情況下,問題纔會發生。

簡而言之,您可以看到它,因爲數據庫以sql語句爲關鍵字緩存查詢計劃。只要更改sql語句,它就不會在緩存中,並且必須生成新的計劃。

所以生成動態之類的語句

"SELECT * FROM table WHERE param = @paramvalue" 

有更好的機會在緩存比

"SELECT * FROM table WHERE param = '" + variable + "'" 

你也應該在查詢中添加架構名稱,表名(例如dbo.table )。否則,如果計劃由不同的登錄執行,計劃將不會被重用。

+0

+1,應該注意的是,SQL Server試圖將後一類型的查詢轉換爲內部的參數化查詢以執行計劃緩存 – Paolo 2010-05-11 09:44:05