この記事では、データベーススコープの構成とSQLServer2017の自動計画修正について説明します。 Microsoftは、クエリのパフォーマンスを向上させる新機能をSQLServer2017に追加しました。
SQL Serverクエリのパフォーマンスは、実行プランの品質と正確さに関係しています。クエリを実行すると、クエリオプティマイザは多くの実行プランを分析し、最適なクエリ実行プランを決定します。
レガシーカーディナリティの推定: Cardinality Estimatorは、クエリが返す行数を予測し、クエリのメモリ割り当てを決定します。
SQL Server 2017では、デフォルトのカーディナリティ推定モデルのバージョンは14.0ですが、カーディナリティ推定の古いバージョン7.0を使用する場合は、データベーススコープ構成のレガシーカーディナリティ推定オプションを変更することでこれを行うことができます。強い> セクション。
LegacyCardinalityEstimationのデフォルト値はOFFです。したがって、古いバージョンを使用する場合は、オンに切り替える必要があります。
または、T-SQLでこのプロパティを変更することもできます。
ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = OFF|ON;
ただし、この設定を有効にすると、すべてのクエリに影響します。その結果、クエリのパフォーマンスが低下する可能性があります。これを防ぐには、FORCE_LEGACY_CARDINALITY_ESTIMATIONヒントを使用できます。
WideWorldImportersデータベースでこのクエリを実行すると、新しいバージョンのカーディナリティ推定が自動的に使用されます。
SELECT [o].[CustomerID], o.LastEditedBy , [o].[OrderDate] FROM Sales.Orders o WHERE [o].[OrderDate] >= '20140101'
クエリにFORCE_LEGACY_CARDINALITY_ESTIMATIONを追加すると、クエリオプティマイザはカーディナリティ推定の以前のバージョンまたは最も古いバージョンを使用します。
MAXDOP : 個々のデータベースの並列処理の最大度を設定できます。この機能が作成される前は、MAXDOPサーバーレベルしか構成できませんでした。
MAXDOPクエリヒントを使用すると、クエリを並行して実行できます。
ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 4; GO
パラメータスニッフィング: クエリの実行時間が大幅に変化し、この時間の変化がクエリパラメータに関連している場合、それはパラメータスニッフィングと呼ばれます。
次に、AdventureWorksデータベースにストアドプロシージャを作成します。さまざまなパラメータを送信し、実行計画を比較します。
DROP PROCEDURE IF EXISTS Get_Orders GO CREATE PROCEDURE Get_Orderes @ProductID INT AS SELECT SalesOrderDetailID, OrderQty FROM Sales.SalesOrderDetail WHERE ProductID = @ProductID; GO /******* Don t use this script in production servers! *******/ DBCC FREEPROCCACHE --Query Mars EXEC Get_OrderID_OrderQty @ProductID=870 DBCC FREEPROCCACHE --Query Venus EXEC Get_OrderID_OrderQty @ProductID=897
次の画像に示すように、SQLServerは同じクエリに対して異なる実行プランを生成します。 Query Mars実行プランは、インデックスを推奨します。クエリパラメータは、最適な実行プランを変更します。
このクエリを実行し、実行計画を確認します。
DBCC FREEPROCCACHE --Query Mars EXEC Get_OrderID_OrderQty @ProductID=870 --Query Venus EXEC Get_OrderID_OrderQty @ProductID=897
Query Venusの実行プランは、QueryMarsの実行プランと同じです。キャッシュされた実行プランはQueryMars実行プラン用にコンパイルされるため、これはパラメータスニッフィングです。このため、QueryVenusは同じ実行プランを使用します。
次に、パラメータスニッフィングを無効にして、同じクエリを実行します。
ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SNIFFING =OFF; DBCC FREEPROCCACHE --Query Mars EXEC Get_OrderID_OrderQty @ProductID=870 --Query Venus EXEC Get_OrderID_OrderQty @ProductID=897
調べてみましょう:
SQL Serverクエリオプティマイザは、クエリ金星とクエリ火星の最適な実行プランを生成しました。このアプローチは、クエリに最適なパフォーマンスを提供します。
この問題を回避するためのいくつかのオプションがあります:
- オプション(再コンパイル)
- オプション(OPTIMIZE FOR(@ VARIABLE =UNKNOWN))
自動プラン修正
SQL Server 2017には、自動計画修正と呼ばれる新機能が含まれています。クエリを実行すると、クエリオプティマイザが実行プランを作成します。いくつかの理由で、クエリオプティマイザは間違った実行プランを選択します。いくつかの理由は次のとおりです。
- パフォーマンス基準を満たさないクエリ
- 古い統計
- 不適切なインデックス
SQL Serverクエリオプティマイザーが実行プランを変更することを決定し、この実行プランがパフォーマンスを損なう場合、クエリパフォーマンスはプランリグレッションと呼ばれます。 SQL Server 2016には新機能が付属しています。このツールは、クエリパフォーマンスの監視とトラブルシューティングに役立ち、同時にクエリ実行のパフォーマンスメトリックとカウンターを保存します。
これらのオプションは、データベースのプロパティで有効にできます。
次に、この機能のデモを作成します。まず、プロシージャキャッシュをクリアして、ストアドプロシージャを作成します。
/**************************************** Don t use this script in production servers *****************************************/ USE WideWorldImporters ALTER DATABASE WideWorldImporters SET QUERY_STORE = ON; ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR ALL DBCC FREEPROCCACHE --This command will clear all procedure cache in SQL Server. Dont try in production envoierment-- ALTER DATABASE WideWorldImporters SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF); DROP PROCEDURE IF EXISTS Test_CoddingSight2 GO CREATE PROC Test_CoddingSight2 @Id AS INT AS select sum([UnitPrice]*[Quantity]) from Sales.OrderLines O INNER JOIN sales.Orders o1 ON o1.OrderID = o.OrderID where o.PackageTypeID = @Id
このステップでは、さまざまなパラメータを使用してこの手順を実行し、実行時間の差を見つけます。
--Query Alpha DBCC FREEPROCCACHE EXEC Test_CoddingSight2 7 GO 80 DBCC FREEPROCCACHE EXEC Test_CoddingSight2 -1 --Query Beta EXEC Test_CoddingSight2 7 GO 80
ご覧のとおり、最初のクエリは12秒で完了し、2番目のクエリは33秒で完了しました。この劇的な違いの理由は、クエリオプティマイザがクエリベータに不適切な実行プランを選択するためです。
クエリアルファとクエリベータの実行計画を比較してみましょう。
クエリアルファの実行プラン
クエリベータの実行プラン
上の画像では、クエリオプティマイザが同じクエリに対して異なる実行プランを作成しています。 クエリを消費するトップリソースを見ると 、QueryBetaはQueryAlphaよりも多くのリソースを消費していることがわかります。
以下のクエリは、チューニングの推奨事項に関する詳細情報を返します。
SELECT name, reason, score, JSON_VALUE(details, '$.implementationDetails.script') as script, details.* FROM sys.dm_db_tuning_recommendations CROSS APPLY OPENJSON(details, '$.planForceDetails') WITH ( query_id int '$.queryId', regressed_plan_id int '$.regressedPlanId', last_good_plan_id int '$.recommendedPlanId') as details WHERE JSON_VALUE(state, '$.currentValue') = 'Active'
理由の列は、この推奨事項を適用する必要がある理由を示しています。
次に、自動プラン修正を有効にして、QueryAlphaとQueryBetaを再実行します。
/**************************************** Don't use this script in production servers *****************************************/ ALTER DATABASE [WideWorldImporters] SET QUERY_STORE CLEAR ALL DBCC FREEPROCCACHE /**************************************** Enable Automatic Plan Correction *****************************************/ ALTER DATABASE WideWorldImporters SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = ON); --Query Alpha DBCC FREEPROCCACHE EXEC Test_CoddingSight2 7 GO 80 DBCC FREEPROCCACHE EXEC Test_CoddingSight2 -1 --Query Beta EXEC Test_CoddingSight2 7 GO 80
このデモの後、クエリアルファ実行プランがクエリベータに適用されます。さらに、クエリアルファとクエリベータの実行時間は互いに近いです。以下のクエリは、自動プラン修正ステータスを返します。
SELECT name, reason, score,JSON_VALUE(state, '$.currentValue') as status, JSON_VALUE(details, '$.implementationDetails.script') as script, details.* FROM sys.dm_db_tuning_recommendations CROSS APPLY OPENJSON(details, '$.planForceDetails') WITH ( query_id int '$.queryId', regressed_plan_id int '$.regressedPlanId', last_good_plan_id int '$.recommendedPlanId') as details WHERE JSON_VALUE(state, '$.currentValue') = 'Verifying'
また、強制プランを使用したクエリでいくつかのグラフィカル情報を見つけることができます 。このグラフは、強制クエリプランとクエリを定義します。
参考資料
SQLServer2017での自動プラン修正
カーディナリティ推定