web-dev-qa-db-ja.com

再コンパイルを伴うストアドプロシージャ

私はこのストアドプロシージャを持っています。再コンパイルオプションでの使用は推奨されないことを開発者に伝えたところ、「これは、さまざまなパラメーターでこのSPを呼び出すことができ、オプティマイザーに取得してもらいたかったためです。呼び出しごとの新しいプラン(理想的ではありませんが、古いキャッシュされたプランを使用するよりも、毎回より確実に高速に実行するための試みでした) "

彼らが言っていることは正しいですか?再コンパイルせずにそれを行う方法はありますか

   create PROCEDURE [dbo].[VERIFIER_QUEUE]
   @cas_name varchar(20) = NULL,
   @instance_name varchar(50) = NULL,
   @verifier_id int = NULL,
   @applicant_type VARCHAR(20) = NULL

    WITH RECOMPILE     
    AS

   BEGIN 
SET NOCOUNT ON

DECLARE @cas_name_x varchar(20)
DECLARE @instance_name_x varchar(50)
DECLARE @verifier_id_x int
DECLARE @InstanceId INT
...............
6
sebeid

Michael Greenは正解です。開発者はパラメータスニッフィングを阻止しようとしています。これは、SQL Serverが1つのパラメータ値のセットには最適ですが、他のセットには恐ろしいプランをコンパイルするときに発生します。

プロシージャの_WITH RECOMPILE_ではなく、問題のあるステートメントでOPTION (RECOMPILE)を使用する必要があります。そして、私はローカル変数を「トリック」にすることをお勧めしません-それは単にコードを乱雑にするだけです。シナリオで最も効果的な方法である場合は、最新バージョンで_OPTIMIZE FOR UNKNOWN_を使用することをお勧めします。 (このトピックの詳細については、 Paul Whiteによるこの素晴らしい投稿 を参照してください。)

また、多くのパラメーターがオプションである場合(クエリに_WHERE col = @param or @param IS NULL_のようなものがある)、チェックアウト キッチンシンク -場合によっては、動的SQLの方がはるかに効果的なソリューションになることがあります。残りのコードは表示せず、ローカル変数のトリックをすでに使用していることだけを示しますが、基本的には次のようになります。

_DECLARE @sql NVARCHAR(MAX) = N'SELECT ... FROM ... WHERE 1 = 1';

IF @cas_name IS NOT NULL
  SET @sql += N' AND cas_name = @cas_name';

IF @instance_name IS NOT NULL
  SET @sql += N' AND instance_name = @instance_name';

IF @verified_id IS NOT NULL
  SET @sql += N' AND verifier_id = @verifier_id';

...

SET @sql = @sql + N' OPTION (RECOMPILE);';
PRINT @sql;

EXEC sys.sp_executesql @sql,
  N'@cas_name VARCHAR(20), @instance_name VARCHAR(50), @verifier_id INT, ...',
  @cas_name, @instance_name, @verifier_id, ...;
_

実際に提供されるパラメーターの句のみを追加するこのアプローチは、異なるパラメーターのセットに基づいてプランをキャッシュすることから保護します(たとえば、最初の実行時に_@FirstName_を指定した場合、キャッシュされるその列のシークプランは_@LastName LIKE N'%s%'_)を要求すると、tが役立ちます。最後のOPTION (RECOMPILE);は、同じパラメータのvaluesに基づいて実行ごとに大きく異なる可能性があるプランから保護します(たとえば、_WHERE name LIKE N'%s%'_は_WHERE name LIKE N'Q%'_)とは異なるプラン形状を生成する必要があります。

これは通常、サーバー設定_optimize for ad hoc workloads_で最適に機能します。これは、 here および here について読むことができます。基本的にこれが行うことは、プランが複数回使用されない限り、プランのキャッシュがこれらのわずかなプランのバリエーションでいっぱいになるのを防ぐことです。 (はい、OPTION (RECOMPILE)の場合、要点はありません。ただし、サーバー設定は、残りのアドホッククエリワークロードに悪影響を与えることはありません。 )

ユーザー入力をSQL文字列に連結することを心配する必要がないため(これはすべてのパラメーターが厳密に型指定されているため)、SQLインジェクションからはかなり安全ですが、動的SQLに関する次のトピックを読むのに支障はありません。

6
Aaron Bertrand