適用対象: SQL Server 2022 (16.x) 以降のバージョン
Azure SQL Database
Azure SQL Managed Instance
Microsoft Fabric 内の SQL データベース
パラメーター センシティビティ プラン (PSP) 最適化は、インテリジェントなクエリ処理機能 ファミリの一部です。 パラメーター化クエリに対してプランが 1 つキャッシュされているだけでは、受け取る可能性があるあらゆるパラメーター値に対して最適ではないシナリオに対処します。 これは一様でないデータ分散のケースです。 詳細については、「パラメーターの感度」と「パラメーターと実行プランの再利用」を参照してください。
この問題のシナリオの既存の回避策の詳細については、次を参照してください。
PSP 最適化を使用すると、パラメーター化された 1 つのステートメントに対して複数のアクティブなキャッシュされたプランが自動的に有効になります。 キャッシュされた実行プランは、顧客が指定したランタイム パラメーター値に基づいて、さまざまなデータ サイズに対応します。
パラメーター化について
SQL Server データベース エンジンでは、Transact-SQL (T-SQL) ステートメントでパラメーターまたはパラメーター マーカーを使用することで、新しい Transact-SQL ステートメントと既存のコンパイル済みの実行プランとを照合し、プランの再利用を促進するリレーショナル エンジンの機能が強化されています。 詳細については、「簡易パラメーター化」を参照してください。
データベースのすべての SELECT、INSERT、UPDATE、および DELETE ステートメントをパラメーター化するように指定することで、いくつかの制約はありますが SQL Server の簡易パラメーター化の既定動作をオーバーライドすることもできます。 詳細については、「強制パラメーター化」を参照してください。
PSP 最適化の実装
初回コンパイル時に、列統計ヒストグラムで一様でない分布が識別され、使用可能なすべての述語のうち、最も "リスクのある" パラメーター化された述語が最大 3 つまで評価されます。 つまり、同じクエリ内の複数の述語が条件を満たしている場合、PSP 最適化では上位 3 つが選択されます。 PSP 機能は、評価される述語の数を制限することで、プラン キャッシュおよびクエリ ストア(クエリ ストアが有効化されている場合)にプランが多すぎることによる肥大化を回避します。
対象となるプランの場合、ディスパッチャー式と呼ばれる PSP 最適化ロジックを含むディスパッチャー プランが初回コンパイルで生成されます。 ディスパッチャー プランは、カーディナリティ範囲の境界値の述語に基づいて、クエリ バリアントにマップされます。
Terminology
親クエリ
PSP 最適化でディスパッチャー プランとクエリ バリアントが生成される元のパラメーター化クエリです。 クエリバリアントは親クエリの子クエリです。 クエリ ストアは同じ親クエリに対して複数のディスパッチャプランを時間をかけて保持できます。
ディスパッチャー表現
ランタイム パラメーター値に基づいて述語のカーディナリティを評価し、実行をさまざまなクエリバリアントにルーティングします。
ディスパッチャー プラン
ディスパッチャー式を含むプランは、元のパラメータ化されたクエリ(親クエリとも呼ばれます)のためにキャッシュされます。 ディスパッチャープランは基本的に、機能が選択した述語の集合であり、いくつかの追加情報を加えたものです。 選択された各述語について、ディスパッチャ計画には 上限 境界値と 下限 境界値が含まれます。 これらの値はパラメータ値を異なる バケット や範囲に分割します。 ディスパッチャー プランには、境界値の計算に使用された統計も含まれています。
クエリバリアント
ディスパッチャー プランは、ランタイム パラメーター値に基づいて述語のカーディナリティを評価する際に、それらの値を分類し、コンパイルして実行する個別の子クエリを生成します。 これらの子クエリは、"クエリ バリアント" と呼ばれます。 クエリ バリアントには、プラン キャッシュとクエリ ストアに独自のプランがあります。
プレディケートのカーディナリティ範囲
実行時に、各述語のカーディナリティがランタイム パラメーター値に基づいて評価されます。 ディスパッチャーは、コンパイル時にカーディナリティ値を 3 つの述語カーディナリティ範囲に分類します。 たとえば、PSP 最適化機能では、次の図に示すように、低、中、高のカーディナリティ範囲を表す 3 つの範囲を作成できます。
つまり、パラメーター化されたクエリが最初にコンパイルされると、PSP 最適化機能によってディスパッチャー プランと呼ばれるシェル プランが生成されます。 ディスパッチャー式には、パラメーターのランタイム値に基づいてクエリ バリアントにクエリを分類するロジックがあります。 実際の実行が開始されると、ディスパッチャーは次の 2 つの手順を実行します。
ディスパッチャーは、指定されたパラメーター セットのディスパッチャー式を評価してカーディナリティ範囲を計算します。
ディスパッチャーは、これらの範囲を特定のクエリバリアントにマップし、バリアントをコンパイルして実行します。 複数のクエリバリアントを持つことにより、PSP 最適化機能は、1 つのクエリに対して複数のプランを持つことを実現します。
カーディナリティ範囲の境界は、ディスパッチ プランの ShowPlan XML 内で確認できます。
<Dispatcher>
<ParameterSensitivePredicate LowBoundary="100" HighBoundary="1000000">
<StatisticsInfo Database="[PropertyMLS]" Schema="[dbo]" Table="[Property]" Statistics="[NCI_Property_AgentId]" ModificationCount="0" SamplingPercent="100" LastUpdate="2019-09-07T15:32:16.89" />
<Predicate>
<ScalarOperator ScalarString="[PropertyMLS].[dbo].[Property].[AgentId]=[@AgentId]">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[PropertyMLS]" Schema="[dbo]" Table="[Property]" Column="AgentId" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Column="@AgentId" />
</Identifier>
</ScalarOperator>
</Compare>
</ScalarOperator>
</Predicate>
</ParameterSensitivePredicate>
</Dispatcher>
PSP 最適化によって生成されたヒントは、クエリバリアントの ShowPlan XML の SQL ステートメントに追加されます。 ヒントを直接使用することはできません。手動で追加した場合は解析 されません 。 ヒントには、次の要素が含まれます。
オプション ( PLAN PER VALUE ( ObjectID = (int), QueryVariantID = (int), predicate_range ( [databaseName].[schemaName].[tableName].[columnName] = @paramName, lowBoundaryValue, highBoundaryValue ) ) )
-
ObjectID は、現在のステートメントが含まれているモジュール (つまり、ストアド プロシージャ、関数、トリガー) から取得されます。これは、ステートメントがモジュールから生成されたことを前提とします。 ステートメントが動的 SQL またはアドホック SQL (つまり、
sp_executesql) の結果である場合、ObjectID 要素は等しくなります0。 - QueryVariantID は、PSP 最適化が選択したすべての述語の範囲の組み合わせとほぼ同じです。 たとえば、クエリに PSP の対象となる 2 つの述語があり、各述語に 3 つの範囲がある場合、9 個のクエリバリアント範囲の番号は 1 から 9 になります。
- 述語範囲 は、ディスパッチャー式から生成される述語カーディナリティ範囲情報です。
クエリバリアントの ShowPlan XML の中にある Dispatcher 要素に関しては、次のとおりです。
<Batch>
<Statements>
<StmtSimple StatementText="SELECT PropertyId,
 AgentId,
 MLSLinkId,
 ListingPrice,
 ZipCode,
 Bedrooms,
 Bathrooms
FROM dbo.Property
WHERE AgentId = @AgentId
ORDER BY ListingPrice DESC option (PLAN PER VALUE(ObjectID = 613577224, QueryVariantID = 1, predicate_range([PropertyMLS].[dbo].[Property].[AgentId] = @AgentId, 100.0, 1000000.0)))" StatementId="1" StatementCompId="2" StatementType="SELECT" StatementSqlHandle="0x090085E4372DFC69BB9E7EBA421561DE8E1E0000000000000000000000000000000000000000000000000000" DatabaseContextSettingsId="1" ParentObjectId="0" StatementParameterizationType="1" RetrievedFromCache="false" StatementSubTreeCost="0.021738" StatementEstRows="3" SecurityPolicyApplied="false" StatementOptmLevel="FULL" QueryHash="0x476167A000F589CD" QueryPlanHash="0xDE982107B7C28AAE" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="160">
<StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false" />
<Dispatcher>
<ParameterSensitivePredicate LowBoundary="100" HighBoundary="1e+06">
<StatisticsInfo LastUpdate="2019-09-07T15:32:16.89" ModificationCount="0" SamplingPercent="100" Statistics="[NCI_Property_AgentId]" Table="[Property]" Schema="[dbo]" Database="[PropertyMLS]" />
<Predicate>
<ScalarOperator ScalarString="[PropertyMLS].[dbo].[Property].[AgentId]=[@AgentId]">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[PropertyMLS]" Schema="[dbo]" Table="[Property]" Column="AgentId" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Column="@AgentId" />
</Identifier>
</ScalarOperator>
</Compare>
</ScalarOperator>
</Predicate>
</ParameterSensitivePredicate>
</Dispatcher>
</StmtSimple>
</Statements>
</Batch>
Remarks
SQL Server 2025 (17.x) およびデータベース互換性 170 以降、PSP 最適化には次の 4 つの機能強化が含まれています。
- DELETE、INSERT、MERGE、UPDATEなどのデータ操作言語(DML)文のサポート。
-
tempdbのサポートが拡張されました。 - 同じテーブルから複数の適格条件を選択し、各列につき最大1つの条件を選択することをサポートしています。
- SQL Server 2025 (17.x) およびデータベース互換性レベル
query_with_parameter_sensitivityでの変更前に、interesting_predicate_count、max_skewness、psp_optimization_supported、および query_type フィールドを含んでいた 拡張イベントへの変更。 ただし、interesting_predicate_count、interesting_predicate_details、psp_optimization_supported、および query_type フィールドを含めます。 詳細については、「 拡張イベント 」セクションを参照してください。
現在、PSP 最適化機能は等価述語でのみ機能します。
データ分散が大幅に変更された場合、ディスパッチャー プランは自動的に再構築されます。 クエリ バリアント プランは、他の種類のクエリ プランと同じように、必要に応じて個別に再コンパイルされ、既定の再コンパイル イベントが適用されます。 再コンパイルの詳細については、「実行プランの再コンパイル」を参照してください。
sys.query_store_plan クエリ ストア システム カタログ ビューは、通常のコンパイル済みプラン、ディスパッチャー プラン、およびクエリバリアント プランを区別するように変更されました。 新しいクエリ ストア システム カタログ ビュー sys.query_store_query_variantには、元のパラメーター化されたクエリ (親クエリとも呼ばれます)、ディスパッチャー プラン、およびその子クエリバリアント間の親子関係に関する情報が含まれています。
データベース互換性レベル160では、同じテーブル参照に複数の適格述語が存在する場合、PSP最適化は基礎となる統計ヒストグラムに基づき、最もデータ歪みが多い述語を選択します。 例えば、
SELECT * FROM table1 WHERE column1 = @predicate1 AND column2 = @predicate2では、両方の述語が同じ表を参照しているため、最も偏った述語のみが選ばれます。 しかし、クエリがテーブルを複数回参照する場合、例えばUNIONの別々のブランチや自己結合のエイリアスを通じて、PSP最適化は複数のテーブル参照から述語を選択することができます。SQL Server 2025(17.x)とデータベース互換性レベル170からは、PSP最適化で同じテーブルから複数の適格な述語を選択することが可能になりました。 各列につき1つの述語のみが選択され、クエリで選択される述語の総数は3つに制限されます。 例えば、
SELECT * FROM table1 WHERE column1 = @predicate1 AND column2 = @predicate2では、PSP最適化の基準を満たす場合、両方の述語を選択できます。クエリバリアントの ShowPlan XML は次の例のようになります。選択された両方の述語には、それぞれの情報が
PLAN PER VALUE PSPに関連するヒントに追加されています。<Batch> <Statements> <StmtSimple StatementText="SELECT b.PropertyId, 
 AgentId, 
 MLSLinkId, 
 ListingPrice, 
 ZipCode, 
 Bedrooms, 
 Bathrooms 
FROM dbo.AgentProperty a join PropertyDetails b on a.PropertyId = b.PropertyId
WHERE AgentId = @AgentId and Property_id=@Property_id
UNION
 SELECT c.PropertyId, 
 AgentId, 
 MLSLinkId, 
 ListingPrice, 
 ZipCode, 
 Bedrooms, 
 Bathrooms 
FROM dbo.AgentProperty c join PropertyDetails d on c.PropertyId = d.PropertyId
WHERE AgentId = @AgentId and Property_id=@Property_id option (PLAN PER VALUE(ObjectID = 981578535, QueryVariantID = 9, predicate_range([PropertyMLS].[dbo].[AgentProperty].[AgentId] = @AgentId, 100.0, 1000000.0),predicate_range([PropertyMLS].[dbo].[AgentProperty].[AgentId] = @AgentId, 100.0, 1000000.0)))" StatementId="1" StatementCompId="2" StatementType="SELECT" StatementSqlHandle="0x090051FBCD918F8DFD60D324887356B422D90000000000000000000000000000000000000000000000000000" DatabaseContextSettingsId="2" ParentObjectId="0" StatementParameterizationType="1" RetrievedFromCache="false" StatementSubTreeCost="29.2419" StatementEstRows="211837" SecurityPolicyApplied="false" StatementOptmLevel="FULL" QueryHash="0x6D2A4E407085C01E" QueryPlanHash="0x72101C0A0DD861AB" CardinalityEstimationModelVersion="160" BatchModeOnRowStoreUsed="true"> <StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false" /> <Dispatcher> <ParameterSensitivePredicate LowBoundary="100" HighBoundary="1e+06"> <StatisticsInfo LastUpdate="2022-08-11T20:42:35.02" ModificationCount="0" SamplingPercent="100" Statistics="[NCI_AgentProperty_AgentId]" Table="[AgentProperty]" Schema="[dbo]" Database="[PropertyMLS]" /> <Predicate> <ScalarOperator ScalarString="[PropertyMLS].[dbo].[AgentProperty].[AgentId] as [a].[AgentId]=[@AgentId]"> <Compare CompareOp="EQ"> <ScalarOperator> <Identifier> <ColumnReference Database="[PropertyMLS]" Schema="[dbo]" Table="[AgentProperty]" Alias="[a]" Column="AgentId" /> </Identifier> </ScalarOperator> <ScalarOperator> <Identifier> <ColumnReference Column="@AgentId" /> </Identifier> </ScalarOperator> </Compare> </ScalarOperator> </Predicate> </ParameterSensitivePredicate> <ParameterSensitivePredicate LowBoundary="100" HighBoundary="1e+06"> <StatisticsInfo LastUpdate="2022-08-11T20:42:35.02" ModificationCount="0" SamplingPercent="100" Statistics="[NCI_AgentProperty_AgentId]" Table="[AgentProperty]" Schema="[dbo]" Database="[PropertyMLS]" /> <Predicate> <ScalarOperator ScalarString="[PropertyMLS].[dbo].[AgentProperty].[AgentId] as [c].[AgentId]=[@AgentId]"> <Compare CompareOp="EQ"> <ScalarOperator> <Identifier> <ColumnReference Database="[PropertyMLS]" Schema="[dbo]" Table="[AgentProperty]" Alias="[c]" Column="AgentId" /> </Identifier> </ScalarOperator> <ScalarOperator> <Identifier> <ColumnReference Column="@AgentId" /> </Identifier> </ScalarOperator> </Compare> </ScalarOperator> </Predicate> </ParameterSensitivePredicate> </Dispatcher> <QueryPlan CachedPlanSize="160" CompileTime="17" CompileCPU="17" CompileMemory="1856" QueryVariantID="9">PSP の最適化機能で使用される現在のスキューしきい値に影響を与えるためには、次の方法の1つ以上を使用することができます。
カーディナリティ推定 (CE) トレース フラグ、たとえばトレース フラグ 9481(グローバル、セッション、またはクエリ レベル)
データベースにスコープした構成 オプションは、使用中の CE モデルを簡略化したり、複数の述語の独立性に関して CE モデルが採用している仮定に影響を与えようとするものです。 これは、複数列の統計情報が存在しない場合に特に役立ちます。このような状況では、PSP 最適化によるそれらの述語の候補性の評価能力に影響します。
詳細については、「SQL Server 2014 カーディナリティ推定機能を使用したクエリ プランの最適化」ホワイト ペーパーの「複数述語の相関の増加の前提条件」セクションを参照してください。 新しい CE モデルでは、述語の結合と結合に対して、ある程度の相関関係とより低い独立性を想定しようとします。 従来の CE モデルを使用すると、複数列結合シナリオでの述語の選択度を計算する方法に影響を与える可能性があります。 このアクションは特定のシナリオでのみ考慮する必要があり、ほとんどのワークロードでレガシ CE モデルを使用することはおすすめしません。
PSP最適化は、各クエリバリアントを別々のプリペアドステートメントとしてコンパイル・実行します。 クエリバリアントプランはキャッシュして再利用できるため、毎回新しいコンパイルが不要です。 クエリバリアントは別々の準備済み文であるため、親クエリがモジュールの一部である場合(ストアドプロシージャ、トリガー、関数など)、そのプランキャッシュ
object_id値は親モジュールを識別しません。 プリペアドステートメントの場合、プランキャッシュobject_idは本質的にバッチテキストの内部ハッシュに基づいて計算された値であり、sys.objects内のオブジェクトの ID ではありません。 詳細については、Table Returned セクションのsys.dm_exec_plan_attributesDMV ドキュメントを参照してください。クエリバリアントプランはSQL Planキャッシュストア(
CACHESTORE_SQLCP)に配置されます。 ディスパッチャー プランは元のバッチまたはモジュールのキャッシュされたプランの一部として残ります。 親クエリがストアドプロシージャまたは、コンパイル済みプランがオブジェクト プラン キャッシュ ストア (CACHESTORE_OBJCP) に格納されている別のモジュールの一部である場合、ディスパッチャ プランはCACHESTORE_OBJCPに格納されます。 親クエリがパラメータ化された動的SQLや該当するアドホックバッチの一部であれば、ディスパッチャプランはCACHESTORE_SQLCPに保存されます。PSP機能は、ShowPlan XMLの
object_idヒントの一部であるObjectID属性内に、クエリ バリアントの親モジュールのPLAN PER VALUEを格納します。 親クエリが動的またはアドホックの T-SQL であれば、この属性は0です。 キャッシュされたプロシージャ、関数、トリガーの集計パフォーマンス統計は、それぞれの目的で引き続き使用できます。sys.dm_exec_query_statsDMVのようなより細かな実行関連統計は、クエリバリアントのデータも含まれます。 しかし、これらの統計を親モジュールに関連付けるには、クエリバリアントのプランキャッシュobject_idでは親モジュールを直接識別できないため、ShowPlan XMLの追加処理が必要です。 クエリバリアントのランタイムおよび待機統計は、クエリ ストアが有効であれば追加のShowPlan XML解析なしでクエリ ストアから取得できます。親モジュールのオブジェクトIDは、クエリバリアントの
sys.dm_exec_*としてプランキャッシュ関連のobject_idDMVsでは直接公開されません。 ディスパッチャーを含むキャッシュされたモジュール プランはモジュールのオブジェクト ID を保持します。 クエリ バリアントの場合、親モジュールのオブジェクト ID は、ShowPlan XML を処理することで、ObjectIDヒント内のPLAN PER VALUE属性から取得できます。 クエリ ストアはこれらの関係を特定するためのリレーショナルモデルを提供します。 sys.query_store_query_variantカタログビューは、元のパラメータ付きクエリをparent_query_idで、ディスパッチャープランをdispatcher_plan_idで、子クエリをquery_variant_query_idで識別します。
Considerations
PSPの最適化を有効にするには、クエリを実行する際に接続しているデータベースの互換性レベル160以上を使いましょう。 SQL Server 2025(17.x)で導入されたPSP最適化の強化は、データベース互換性レベル170以上が必要です。
PSP 最適化機能の追加の分析情報を得るには、クエリ ストア統合も有効にすることをおすすめします。それにはクエリ ストアを確実にオンにしてください。 次の例では、
MyNewDatabaseと呼ばれる既存のデータベースのクエリ ストアを有効にします。
ALTER DATABASE [MyNewDatabase]
SET QUERY_STORE = ON (
OPERATION_MODE = READ_WRITE,
QUERY_CAPTURE_MODE = AUTO
);
Note
クエリ ストアは、SQL Server 2022 (16.x) 以降の時点で、新しく作成されたデータベースに対して既定で有効になっています。
データベース レベルで PSP 最適化を無効にするには、
ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SENSITIVE_PLAN_OPTIMIZATION = OFFデータベース スコープ構成を使用します。クエリ レベルで PSP 最適化を無効にするには、
DISABLE_PARAMETER_SENSITIVE_PLANクエリ ヒントを使用します。パラメーター スニッフィングがトレース フラグ 4136、
PARAMETER_SNIFFINGデータベース スコープ構成、またはUSE HINT('DISABLE_PARAMETER_SNIFFING')クエリ ヒントによって無効になっている場合、関連付けられているワークロードと実行コンテキストに対して PSP 最適化が無効になります。 詳細については、「 クエリ ヒント と ALTER DATABASE SCOPED CONFIGURATION」を参照してください。ディスパッチャーごとにプラン キャッシュ内に保存される一意のプラン バリアント数は、キャッシュの肥大化を回避するために制限されています。 内部しきい値は文書化されていません。 各 SQL バッチには複数のプランを作成する可能性があり、各クエリ バリアント プランにはプラン キャッシュに独立したエントリがあるため、許可されるプラン エントリの既定の最大数に達する可能性があります。 プラン キャッシュの削除率が著しく高い場合、または
CACHESTORE_OBJCPおよびCACHESTORE_SQLCPcache ストア のサイズが過剰な場合は、 トレース フラグ 174 の適用を検討する必要があります。クエリのためにクエリ ストア内に保存される一意のプラン バリアント数は、
max_plans_per_query構成オプションによって制限されています。 クエリ バリアントには複数のプランを含めることができるので、クエリ ストア内のクエリごとに合計 200 個のプランを使用できます。 この数値には、親クエリに属するすべてのディスパッチャーのすべてのクエリ バリアント プランが含まれます。max_plans_per_queryクエリ ストアの構成オプションを増やすことを検討してください。- 一意のプランの数が既定のクエリ ストア
max_plans_per_queryの制限を超える可能性がある例は、次の動作が発生するシナリオです。 クエリ ID が 10 のクエリがあり、ディスパッチャー プランが 2 つあり、各ディスパッチャー プランにそれぞれ 20 個のクエリ バリアント (合計で 40 個のクエリ バリアント) があるとします。 クエリ ID 10 のプランの合計数は、クエリ バリアントと 2 つのディスパッチャー プランの 40 プランです。 また、親クエリ自体 (クエリ ID 10) に 5 つの標準 (ディスパッチャー以外) プランを含めることもできます。 これにより、47 個のプラン (クエリ バリアントから 40 個、ディスパッチャー 2 個、PSP 以外のプランが 5 つ) になります。 さらに、各クエリ バリアントに平均 5 つのプランがある場合、このシナリオでは、親クエリのクエリ ストアに 200 を超えるプランがある可能性があります。 これは、この例の親クエリが参照している可能性があるデータセットのデータ スキューの大きい値にも依存します。
- 一意のプランの数が既定のクエリ ストア
特定のディスパッチャーへのクエリ バリアント マッピングごとに、次の手順を実行します。
-
query_plan_hashは一意です。 この列は、sys.dm_exec_query_statsと、その他の動的管理ビューおよびカタログ テーブルで使用できます。 -
plan_handleは一意です。 この列は、sys.dm_exec_query_stats、sys.dm_exec_sql_text、sys.dm_exec_cached_plansと、その他の動的管理ビューと関数およびカタログ テーブルで使用できます。 -
query_hashは、同じディスパッチャーにマップされる他のバリアントに共通であるため、入力パラメーター値のみが異なるクエリを合計したリソース使用率を特定できます。 この列は、sys.dm_exec_query_stats、sys.query_store_queryと、その他の動的管理ビューおよびカタログ テーブルで使用できます。 - コンパイル時に特別な PSP 最適化識別子がクエリ テキストに追加されるため、
sql_handleは一意です。 この列は、sys.dm_exec_query_stats、sys.dm_exec_sql_text、sys.dm_exec_cached_plansと、その他の動的管理ビューと関数およびカタログ テーブルで使用できます。last_compile_batch_sql_handleカタログ テーブルのsys.query_store_query列と同じハンドル情報をクエリ ストアで使用できます。 -
query_idは、クエリ ストア内で一意です。 この列は、sys.query_store_queryと、その他のクエリ ストア カタログ テーブルで使用できます。
-
クエリ ストアにおけるプランの強制
同じ sp_query_store_force_plan および sp_query_store_unforce_plan ストアド プロシージャを使用して、ディスパッチャーまたはバリアント プランを操作します。
クエリバリアントプランを強制しても、それに対応するディスパチャープランは強制されません。 ディスパッチャーが強制されている場合、そのディスパッチャーのバリアントのみが使用できると見なされます。
- 他のディスパッチャーから以前に強制されたバリアントは非アクティブになりますが、ディスパッチャーが再度強制されるまで、"強制" 状態を保持します
- 非アクティブになっていたのと同じディスパッチャーで以前に強制されたバリアントが、再度強制されます
クエリ ストアのクエリ ヒントの動作
クエリ ストア ヒントがクエリ バリアント (子クエリ) に追加されると、ヒントは PSP 以外のクエリと同じ方法で適用されます。 クエリ ストアの親クエリにもヒントが適用されている場合、クエリ バリアント ヒントの優先順位が高くなります。
クエリ ストア ヒントが親クエリに追加され、子クエリ (クエリバリアント) に既存のクエリ ストア ヒントがない場合、子クエリ (クエリバリアント) は親クエリからヒントを継承します。
クエリ ストアのクエリ ヒントが親クエリから削除された場合、子クエリ (クエリ バリアント) にもヒントが削除されます。
RECOMPILEヒントが親クエリに追加された場合、PSP 機能はRECOMPILEヒントを持つクエリに対して動作しないため、既存のクエリバリアント プランがプラン キャッシュから削除された後に、システムによって PSP 以外のプランが生成されます。クエリ ストア ヒントの結果は、拡張イベント
query_store_hints_application_successとquery_store_hints_application_failedイベントを使用して確認できます。 sys.query_store_query_hints テーブルには、適用されたクエリ ヒントに関する情報が含まれています。 ヒントが親クエリにのみ適用されている場合、システム カタログには親クエリのヒント情報が含まれますが、子クエリは親クエリのヒントを継承しますが、子クエリのヒントは含まれません。
クエリ ヒントとプラン強制動作を含む PSP を次の表にまとめることができます。
| クエリのバリアント、ヒント、またはプラン | 親にユーザーが設定したヒントがある | 親にフィードバックが適用されたヒントがある | 親が手動で計画を強制している | 親の強制プランとしてAPC1が設定されています |
|---|---|---|---|---|
| ユーザーによるヒント | クエリバリアントヒント | クエリバリアントヒント | クエリバリアントヒント | N/A |
| フィードバックによるヒント | クエリバリアントヒント | クエリバリアントヒント | クエリバリアントヒント | N/A |
| ユーザーによる強制的な計画 | クエリバリアント 強制プラン |
クエリバリアント 強制プラン |
クエリバリアント 強制プラン |
クエリバリアント 強制プラン |
| APC によって強制される計画 | クエリバリアント 強制プラン |
クエリバリアント 強制プラン |
クエリバリアント 強制プラン |
クエリバリアント 強制プラン |
| ヒントまたは強制プランなし | 親ユーザーのヒント | ヒントなし | アクションなし | アクションなし |
1 自動チューニング機能の自動プラン修正コンポーネント
拡張イベント
parameter_sensitive_plan_optimization_skipped_reason: パラメーター センシティビティ プラン機能がスキップされたときに発生します。 このイベントを使用して、PSP の最適化がスキップされる理由を監視します。次のクエリは、PSP がスキップされた可能性のあるすべての理由を示しています。
SELECT map_value FROM sys.dm_xe_map_values WHERE [name] = 'psp_skipped_reason_enum' ORDER BY map_key;parameter_sensitive_plan_optimization: クエリで PSP 最適化機能が使用されている場合に発生します。 デバッグ チャネルのみ。 関心のあるフィールドには、次の項目があります。- is_query_variant: ディスパッチャー プラン (親) またはクエリバリアント プラン (子) のどちらであるかについて説明します
- predicate_count: PSP によって選択された述語の数
- query_variant_id: クエリバリアント ID が表示されます。 値 0 は、オブジェクトがディスパッチャー プラン (親) であることを意味します。
query_with_parameter_sensitivity: このイベントが発生すると、特徴が興味深いと見なした述語の数、興味深い述語に関する json 形式の詳細、および述語または述語に対して PSPO がサポートされているかどうかが表示されます。query_with_parameter_sensitivity拡張イベントからの出力例
| Field | Value |
|---|---|
| interesting_predicate_count | 3 |
| interesting_predicate_details | {"Predicates":[{"ColumnId":7,"TableId":1221579390,"Skewness":475038.75},{"ColumnId":7,"TableId":1221579390,"Skewness":475038.75},{"ColumnId":7,"TableId":1221579390,"Skewness":475038.75}]} |
| psp_optimization_supported | True |
| query_type | 195 |
SQL Server 監査の動作
PSP の最適化では、ディスパッチャー プラン ステートメントと、ディスパッチャーに関連付けられているクエリバリアントの監査データが提供されます。 SQL Server 監査内の additional_information 列には、クエリバリアントに対する適切な T-SQL スタック情報も用意されています。
MyNewDatabase データベースを例として使用すると、このデータベースに T2 と呼ばれるテーブルが呼び出され、usp_test の名前がストアド プロシージャである場合、usp_test ストアド プロシージャの実行後に、監査ログに次のエントリが含まれる場合があります。
| action_id | object_name | ステートメント | additional_information |
|---|---|---|---|
| AUSC | <action_info xmlns="http://schemas.microsoft.com/sqlserver/2008/sqlaudit_data"><session><![CDATA[Audit_Testing_Psp$A]]></session><action>event enabled</action><startup_type>manual</startup_type><object><![CDATA[audit_event]]></object></action_info> |
||
| EX | usp_test | exec usp_test 300 (実行コマンド例: EXECによって300のテストを行う) | |
| SL | T2 | 論理演算子や条件を使用して、dbo.t2 テーブルから ID に基づいてデータを選択します。SQL コード: select * from dbo.t2 where ID=@id | <tsql_stack><frame nest_level = '1' database_name = 'MyNewDatabase' schema_name = 'dbo' object_name = 'usp_test'/></tsql_stack> |
| SL | T2 | select * from dbo.t2 where ID=@id option (PLAN PER VALUE(ObjectID = 933578364, QueryVariantID = 1, predicate_range([MyNewDatabase].[dbo].[T2].[ID] = @id, 100.0, 100000.0))) | tsql_stack><frame nest_level = '1' database_name = 'MyNewDatabase' schema_name = 'dbo' object_name = 'usp_test'/></tsql_stack> |
| EX | usp_test | exec usp_test 60000 | |
| SL | T2 | 論理演算子や条件を使用して、dbo.t2 テーブルから ID に基づいてデータを選択します。SQL コード: select * from dbo.t2 where ID=@id | <tsql_stack><frame nest_level = '1' database_name = 'MyNewDatabase' schema_name = 'dbo' object_name = 'usp_test'/></tsql_stack> |
| SL | T2 | select * from dbo.t2 where ID=@id option (PLAN PER VALUE(ObjectID = 933578364, QueryVariantID = 3, predicate_range([TestDB_FOR_PSP].[dbo].[T2].[ID] = @id, 100.0, 100000.0))) | <tsql_stack><frame nest_level = '1' database_name = 'MyNewDatabase' schema_name = 'dbo' object_name = 'usp_test'/></tsql_stack> |
既知の問題
| Issue | 検出した日 | Status | 解決した日 |
|---|---|---|---|
| 「特定の条件下で SQL Server 2022 (16.x) のクエリ ストアで発生するアクセス違反の例外」。 PSP 最適化クエリ ストア統合が有効になっていると、アクセス違反の例外が発生する可能性があります。 詳細については、「パラメーターの機密性の高いプランの最適化」の「理由」の更新を参照してください。 | 2023 年 3 月 | Resolved | 2023 年 8 月 (SQL Server 2022 CU 7) |
| アクセス違反の例外は、SQL Server 2025 (17.x) の特定の条件下で読み取り可能なセカンダリ レプリカで発生する可能性があります。 読み取り可能なセカンダリ レプリカ機能にクエリ ストアを使用するように構成されている読み取り可能なセカンダリ データベースで PSP 最適化が有効になっている場合、アクセス違反の例外が発生する可能性があります。 | 2025 年 9 月 | Resolved | 2026 年 1 月 (SQL Server 2025 CU 1) |
Resolved
特定の条件下で読み取り可能なセカンダリ レプリカでアクセス違反の例外が発生する可能性がある
(2026 年 1 月に解決済み)
次の条件を満たすクエリでは、パラメーターの機密性の高いプラン (PSP) クエリバリアント が親ディスパッチャー ステートメントの永続化された状態を判断できない場合、アクセス違反が発生する可能性があります。
- セカンダリ レプリカで実行される
- パラメーター スニッフィングの影響を受けやすい
- パラメーターに敏感なプラン (PSP) の最適化の対象として適格
「特定の条件下で SQL Server 2022 のクエリ ストアで発生するアクセス違反の例外」
(2023 年 3 月に解決済み)
Note
SQL Server 2022 (16.x) 累積的な更新プログラム 7 では、アクセス違反につながる可能性がある競合状態に関するいくつかの修正プログラムがリリースされました。
実行されたクエリの実行時統計が、クエリ ストアのメモリ内表現 (MEMORYCLERK_QUERYDISKSTORE_HASHMAP メモリ管理者) からディスク上のクエリ ストアのバージョンに永続化される際に発生するレースコンディションが原因で、この問題が発生しました。 ランタイム統計情報として示されるランタイム統計は、DATA_FLUSH_INTERVAL_SECONDS ステートメントの SET QUERY_STORE オプションで定義された一定期間、メモリ内に保持されます。(既定値は15分です)。 Management Studio クエリ ストア ダイアログ ボックスを使用して、 [データ フラッシュ間隔 (分)] の値を入力できます。これは、内部的に秒に変換されます。 メモリ不足が発生した場合、DATA_FLUSH_INTERVAL_SECONDS オプションで定義されている時間より前に、ランタイム統計がディスクにフラッシュされる可能性があります。 クエリ ストアのクエリ プランのクリーンアップ (STALE_QUERY_THRESHOLD_DAYS または MAX_STORAGE_SIZE_MB のクエリ ストア オプション) に関連する追加のクエリ ストア バックグラウンド スレッドや、クエリスト ストアからのクエリの場合、クエリ バリアントまたはそれに関連付けられたディスパッチャー ステートメントが、予定より早く参照解除されてしまうシナリオがあります。 これにより、クエリ ストアへのクエリ バリアントの挿入または削除操作中にアクセス違反が発生する可能性があります。
クエリ ストアの操作の詳細については、「クエリ ストアでデータを収集する方法」の「 解説 」セクションを参照してください。