使用する場合OPTION (RECOMPILE)
は、実行前 (「推定」) の計画ではなく、実行後 (「実際の」) 計画を確認してください。一部の最適化は、実行時にのみ適用されます。
DECLARE @ForeignKeyCol int = 20;
SELECT ForeignKeyCol, ForeignKeyRank
FROM dbo.ViewOnBaseTable
WHERE ForeignKeyCol = @ForeignKeyCol
OPTION (RECOMPILE);
実行前の計画:
実行後の計画:
SQL Server 2012 ビルド 11.0.3339 および SQL Server 2008 R2 ビルド 10.50.4270 でテスト済み
背景と制限事項
ウィンドウ関数が SQL Server 2005 に追加されたとき、オプティマイザには、これらの新しいシーケンス プロジェクションを超えて選択をプッシュする方法がありませんでした。これによりパフォーマンスの問題が発生するいくつかの一般的なシナリオに対処するために、SQL Server 2008 には新しい単純化ルールが追加されましたSelOnSeqPrj
。これにより、値が定数である場合に適切な選択をプッシュできます。この定数は、クエリ テキスト内のリテラル、または を介して取得されたパラメータのスニッフィング値である可能性がありますOPTION (RECOMPILE)
。NULLs
クエリがこれを確認する必要がある場合がありますが、特に問題はありませんANSI_NULLS OFF
。私の知る限り、単純化を定数値のみに適用することは実装上の制限です。変数を扱うように拡張できない特別な理由はありません。私の記憶では、SelOnSeqPrj
ルールは、最も一般的に見られるパフォーマンスの問題に対処します。
パラメータ化
クエリが正常に自動パラメータ化された場合、SelOnSeqPrj
ルールは適用されません。クエリが SSMS で自動パラメーター化されたかどうかを判断する信頼できる方法はありません。自動パラメーターが試行されたことを示すだけです。明確にするために、 のようなプレースホルダーの存在は、自動パラメーター化が試行されたことを示しているだけです。準備済みプランが再利用のためにキャッシュされたかどうかを確認する信頼できる方法は、「パラメーター化されたプラン ハンドル」がアドホック プランと準備済みプランの間のリンクを提供するプラン キャッシュを調べることです。[@0]
たとえば、次のクエリは、SSMS で自動パラメーター化されているようです。
SELECT *
FROM dbo.ViewOnBaseTable
WHERE ForeignKeyCol = 20;
しかし、プラン キャッシュは別の方法で示しています。
WITH XMLNAMESPACES
(
DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan'
)
SELECT
parameterized_plan_handle =
deqp.query_plan.value('(//StmtSimple)[1]/@ParameterizedPlanHandle', 'nvarchar(64)'),
parameterized_text =
deqp.query_plan.value('(//StmtSimple)[1]/@ParameterizedText', 'nvarchar(max)'),
decp.cacheobjtype,
decp.objtype,
decp.plan_handle
FROM sys.dm_exec_cached_plans AS decp
CROSS APPLY sys.dm_exec_sql_text(decp.plan_handle) AS dest
CROSS APPLY sys.dm_exec_query_plan(decp.plan_handle) AS deqp
WHERE
dest.[text] LIKE N'%ViewOnBaseTable%'
AND dest.[text] NOT LIKE N'%dm_exec_cached_plans%';
強制パラメーター化のデータベース オプションが有効になっている場合、最適化が適用されないパラメーター化された結果が得られます。
ALTER DATABASE Sandpit SET PARAMETERIZATION FORCED;
DBCC FREEPROCCACHE;
SELECT *
FROM dbo.ViewOnBaseTable
WHERE ForeignKeyCol = 20;
プラン キャッシュ クエリは、パラメーター化されたプラン ハンドルによってリンクされた、パラメーター化されたキャッシュされたプランを表示するようになりました。
回避策
可能であれば、ビューをインラインのテーブル値関数として書き直すことをお勧めします。これにより、(必要に応じて) 選択の意図した位置をより明確にすることができます。
CREATE FUNCTION dbo.ParameterizedViewOnBaseTable
(@ForeignKeyCol integer)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT
bt.PrimaryKeyCol,
bt.ForeignKeyCol,
ForeignKeyRank = DENSE_RANK() OVER (
PARTITION BY bt.ForeignKeyCol
ORDER BY bt.PrimaryKeyCol),
bt.DataCol
FROM dbo.BaseTable AS bt
WHERE
bt.ForeignKeyCol = @ForeignKeyCol;
クエリは次のようになります。
DECLARE @ForeignKeyCol integer = 20;
SELECT pvobt.*
FROM dbo.ParameterizedViewOnBaseTable(@ForeignKeyCol) AS pvobt;
実行計画では: