ストアドプロシージャで動的SQLを使用すると、ストアドプロシージャのパフォーマンスが低下する可能性があることを読みました。理論的には、ストアドプロシージャは、EXECまたはsp_executesqlを介して実行されたSQLの実行プランを格納しないということだと思います。
これが本当かどうか知りたいです。それが本当の場合、それぞれが私のSQLステートメントの異なる「バージョン」を持つ複数のネストされたIFブロックで同じ問題が発生しますか?
ストアドプロシージャで動的SQLを使用すると、ストアドプロシージャのパフォーマンスが低下する可能性があることを読みました。理論的には、ストアドプロシージャは、EXECまたはsp_executesqlを介して実行されたSQLの実行プランを格納しないということだと思います。
これが本当かどうか知りたいです。それが本当の場合、それぞれが私のSQLステートメントの異なる「バージョン」を持つ複数のネストされたIFブロックで同じ問題が発生しますか?
ネストされたIFブロックが複数ある場合、SQLServerは実行プランを保存できます。IFは単純であると想定しています。@Parameter1がNULLでない場合
SchmitzITの答えは、SQLServerが動的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テキストは使用するパラメーター値をハードコーディングしていません。それらはexecsp_executesqlで個別に渡されます
古き良き動的sqLを書く場合
set @sqlcommand = N'Select Something from Table where Field1 = ' + @Param1 + ' AND Field2 = ' + @Param2
exec sp_executesql @sqlcommand
その場合、SQLServerは実行プランを保存できなくなります
これはMSDNがそれについて言わなければならないことです。私はあなたの質問に関連するビットを強調しました
sp_executesqlは、バッチ、名前のスコープ、およびデータベースコンテキストに関して、EXECUTEと同じ動作をします。sp_executesql @stmtパラメーターのTransact-SQLステートメントまたはバッチは、sp_executesqlステートメントが実行されるまでコンパイルされません。次に、@ stmtの内容は、sp_executesqlを呼び出したバッチの実行プランとは別の実行プランとしてコンパイルおよび実行されます。sp_executesqlバッチは、sp_executesqlを呼び出すバッチで宣言された変数を参照できません。sp_executesqlバッチ内のローカルカーソルまたは変数は、sp_executesqlを呼び出すバッチには表示されません。データベースコンテキストの変更は、sp_executesqlステートメントの最後まで続きます。
ストアドプロシージャの代わりにsp_executesqlを使用して、ステートメントへのパラメータ値の変更が唯一のバリエーションである場合に、Transact-SQLステートメントを何度も実行できます。Transact-SQLステートメント自体は一定のままであり、パラメーター値のみが変更されるため、SQL Serverクエリオプティマイザーは、最初の実行で生成した実行プランを再利用する可能性があります。