3

特定のクエリを実行するときにオプティマイザがキャッシュされたクエリ プランを使用しないようにするためのヒントはありますか?

特定のプランの使用を強制するためのMSDN ページを見つけましたが、反対のプランが必要です。次のヒントを追加してみました。

OPTION (USE NO PLAN);

それとも、キャッシュの一部を実際にクリアする必要がありますか?

4

1 に答える 1

7

個々のクエリでは、OPTION RECOMPILE クエリ ヒントを使用して、実行ごとに新しいプランを強制できます。次のようになります。

SELECT  T.Column1, T2.Column2
FROM    T
        INNER JOIN T2
            ON T.ID = T2.ID
WHERE   T.Column2 = @SomeParameter
OPTION (RECOMPILE);

または、ストアド プロシージャ レベルでWITH RECOMPILEを使用できます。

CREATE PROCEDURE dbo.TestRecompile @Param INT
WITH RECOMPILE
AS
    SELECT  *
    FROM    dbo.T;

一度だけ再コンパイルからストアド プロシージャをマークしたい場合 (つまり、次回の実行時にキャッシュされたプランを使用しない場合)、SP_RECOMPILEを使用できます。

EXECUTE sp_recompile 'dbo.ProcedureName';

私はMartin Smithが言及した複雑さに気づいていませんでした.私はそれらを再現しようとしましたができませんでした.とにかく結果を追加します。

このスキーマを作成しました:

IF OBJECT_ID(N'dbo.T', 'U') IS NOT NULL
        DROP TABLE dbo.T;
GO
CREATE TABLE dbo.T 
(   ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, 
    Column1 INT NOT NULL, 
    Column2 INT NULL
);
INSERT dbo.T (Column1, Column2)
SELECT  TOP 9999 1, Number
FROM    Master..spt_values
UNION ALL
SELECT  TOP 1001 Number, Number
FROM    Master..spt_values
WHERE   Type ='P';

CREATE NONCLUSTERED INDEX IX_T_Column1 ON dbo.T (Column1 ASC);

column1 = 1select whereではクラスター化インデックス スキャンを使用する必要がありますが、他のすべての条件では非クラスター化インデックスを使用する必要があるため、意図的にテーブルに重みを付けます。コントロールケースは次のとおりです。

DBCC FREEPROCCACHE;
DECLARE @SQL NVARCHAR(MAX) = 'SELECT COUNT(T.Column2) FROM dbo.T WHERE T.Column1 = @ID';
DECLARE @ParamDef NVARCHAR(MAX) =  N'@ID INT';

EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 1;
EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;

これにより、2 つの同一の計画が作成されました。

ここに画像の説明を入力

次のシナリオはOPTION (RECOMPILE)、クエリに追加することでした。

DBCC FREEPROCCACHE;
DECLARE @SQL NVARCHAR(MAX) = '  SELECT  COUNT(T.Column2) 
                                FROM    dbo.T 
                                WHERE   T.Column1 = @ID 
                                OPTION (RECOMPILE);';

DECLARE @ParamDef NVARCHAR(MAX) =  N'@ID INT';

EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 1;
EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;

これにより、@ID = 1 の最初の 2 つの実行プランと同じ実行プランが得られますが、@ID = 2 のブックマーク ルックアップが使用されます。これは、単一の行を取得するときにより効率的なプランです。

ここに画像の説明を入力

NB @ID = 2 で最初に再コンパイルせずに実行した場合、両方のプランは同じままですが、両方とも上記の @ID = 2 のキー ルックアップを使用します。

代わりの別のオプションOPTION (RECOMPILE)は、特定のクエリのキャッシュをクリアすることです。

DBCC FREEPROCCACHE;
DECLARE @SQL NVARCHAR(MAX) = '  SELECT  COUNT(T.Column2)
                                FROM    dbo.T 
                                WHERE   T.Column1 = @ID';
DECLARE @ParamDef NVARCHAR(MAX) =  N'@ID INT';

EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 1;
EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;

DECLARE @PlanHandle VARBINARY(64) = 
                    (   SELECT  TOP 1 PLAN_HANDLE
                        FROM    SYS.DM_EXEC_CACHED_PLANS
                                CROSS APPLY SYS.DM_EXEC_SQL_TEXT(PLAN_HANDLE) AS ST
                        WHERE   ST.TEXT = '(' + @ParamDef + ')' + @SQL
                    );

DBCC FREEPROCCACHE (@PlanHandle);

EXECUTE SP_EXECUTESQL @SQL, @ParamDef, @ID = 2;

ここに画像の説明を入力 ここに画像の説明を入力

最初は (コントロールの場合と同様に)、すべてのパラメーター値に同じプランが使用されますが、特定のクエリ定義のキャッシュをクリアできます。これが完了すると、@ID = 2 にキー ルックアップ プランが使用されます。

したがって、OPTION (RECOMPILE)が期待どおりに機能しない場合は、クエリ テキストのプラン ハンドルを使用して、その特定のクエリのキャッシュをクリアできます。

于 2013-10-02T09:51:49.440 に答える