2012-11-06 103 views
2

我讀過在存儲過程中使用動態SQL可能會損害存儲過程的性能。我想這個理論是,存儲過程不會存儲通過EXEC或sp_executesql執行的SQL的執行計劃。動態SQL和存儲過程優化

我想知道,如果這是真的。如果這是真的,我是否有與多個嵌套的IF塊相同的問題,每個塊都有我的SQL語句的不同「版本」?

回答

6

如果您有多個嵌套的IF塊則SQL Server將能夠存儲的執行計劃。 我假設IF是直接的,例如。 @如果參數1 IS NOT NULL

SchmitzIT的答案是正確的SQL Server還可以存儲用於動態SQL的執行路徑。然而,只有sql被正確構建和執行,這纔是真實的。

通過適當建,我的意思是顯式聲明的參數和傳遞他們對sp_executesql。例如

declare @Param1 nvarchar(255) = 'foo' 
     ,@Param2 nvarchar(255) = 'bar' 
     ,@sqlcommand nvarchar(max) 
     ,@paramList nvarchar(max) 

set @paramList = '@Param1 nvarchar(255), @Param2 nvarchar(255)' 
set @sqlcommand = N'Select Something from Table where Field1 = @Param1 AND Field2 = @Param2' 

exec sp_executesql @statement = @sqlcommand 
        ,@params = @paramList 
        ,@Param1 = @Param1 
        ,@Param2 = @Param2 

正如您所看到的,sqlcommand文本不會硬編碼要使用的參數值。它們在EXEC sp_executesql的

分別通過如果你寫壞舊的動態SQL

set @sqlcommand = N'Select Something from Table where Field1 = ' + @Param1 + ' AND Field2 = ' + @Param2 

exec sp_executesql @sqlcommand 

那麼SQL Server將無法存儲執行計劃

+0

我在考慮是用動態的情況下, SQL來確定在SELECT中使用哪種where子句。 AFAIK,我不能參數化我的查詢,因爲我沒有使用參數作爲字段值。 或者有沒有辦法參數化where子句? – Finster

+1

不,我不認爲where子句可以被參數化,因爲where子句是SQL命令的一部分。這聽起來像你的動態SQL本質上是靜態的,但它有不同的風格。我想你只是想減少代碼重複。我想唯一可以肯定的就是加速測試這兩種風格,但在你的情況下,我希望可以忽略不計的差異。 – DeanOC

+0

@DeanOC你爲什麼在執行級別使用Name = Value方法(例如statement = sqlcommand等)?這不會是相同的exec sp_executesql sqlcommand,paramList,Param1,Param2你指的是正確地構建動態SQL,其中params不是硬編碼,這是這裏的情況。只是好奇! – SQLnbe

3

這是MSDN不得不說些什麼。我強調了相關位對您的問題

sp_executesql的具有如針對批次, 名稱的範圍,數據庫上下文中執行相同的行爲。 直到 的執行sp_executesql語句的Transact-SQL語句 或批處理的sp_executesql的@stmt參數未編譯。 @stmt的內容是 ,然後編譯並執行一個執行計劃,該執行計劃與調用sp_executesql的批處理的 執行計劃分開。 sp_executesql批處理無法引用調用sp_executesql的批處理 中聲明的變量。調用 sp_executesql的批處理對 sp_executesql批處理中的本地遊標或變量不可見。數據庫上下文中的更改僅持續到 sp_executesql語句的末尾。

sp_executesql的可以用來代替的存儲過程時,在參數的變化值 的說法是唯一的變化來執行 的Transact-SQL語句多次。由於的Transact-SQL語句 本身保持不變,僅參數值 變化,SQL Server查詢優化器可能會重用它產生了第一次執行的 執行計劃。

http://msdn.microsoft.com/en-us/library/ms188001.aspx