SQL Server ‐ Automatic Query Tuning - shaysalomon12/Data-Engineer GitHub Wiki
- https://www.mssqltips.com/sqlservertip/5141/sql-server-2017-automatic-query-tuning/
- https://www.sqlshack.com/understanding-automatic-tuning-in-sql-server-2017/
USE [DB_NAME]
GO
ALTER DATABASE CURRENT SET QUERY_STORE = ON;
GO
ALTER DATABASE CURRENT SET QUERY_STORE
(
OPERATION_MODE = READ_WRITE,
DATA_FLUSH_INTERVAL_SECONDS = 600,
MAX_STORAGE_SIZE_MB = 500,
INTERVAL_LENGTH_MINUTES = 30
);
GO
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE CURRENT SET QUERY_STORE CLEAR ALL;
ALTER DATABASE CURRENT
SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = ON );
GO
SELECT * FROM sys.database_automatic_tuning_options
For each query_id we can see if a good plan was:
- Successfully forced (state = Success)
- Failed to force (state = Reverted)
- Expired
SELECT
query_id = JSON_VALUE(details, '$.planForceDetails.queryId'),
reason,
score,
JSON_VALUE(state, '$.currentValue') state,
JSON_VALUE(state, '$.reason') state_transition_reason,
script_to_force_recommendedPlanId = JSON_VALUE(details, '$.implementationDetails.script'),
current_plan_id = JSON_VALUE(details, '$.planForceDetails.regressedPlanId'),
recommended_plan_id = JSON_VALUE(details, '$.planForceDetails.recommendedPlanId'),
current_Plan_Execution_Count = JSON_VALUE(details, '$.planForceDetails.regressedPlanExecutionCount'),
recommended_Plan_Execution_Count = JSON_VALUE(details, '$.planForceDetails.recommendedPlanExecutionCount'),
current_Plan_Cpu_Time_Average_microsec = cast(JSON_VALUE(details, '$.planForceDetails.regressedPlanCpuTimeAverage') as float),
recommended_Plan_Cpu_Time_Average_microsec = cast(JSON_VALUE(details, '$.planForceDetails.recommendedPlanCpuTimeAverage') as float),
current_Plan_Cpu_Time_Stddev_microsec = cast(JSON_VALUE(details, '$.planForceDetails.regressedPlanCpuTimeStddev') as float),
recommended_Plan_Cpu_Time_Stddev_microsec = cast(JSON_VALUE(details, '$.planForceDetails.recommendedPlanCpuTimeStddev') as float),
details
FROM sys.dm_db_tuning_recommendations;
select * from sys.query_store_plan where is_forced_plan=1;
SELECT
qsq.query_id,
qsq.last_execution_time,
qsqt.query_sql_text
FROM sys.query_store_query qsq
INNER JOIN sys.query_store_query_text qsqt
ON qsq.query_text_id = qsqt.query_text_id
WHERE
qsq.query_id = <query_id>;
List queries in the Query Store:
SELECT txt.query_text_id,
txt.query_sql_text,
pl.plan_id,
pl.is_forced_plan,
qry.*
FROM sys.query_store_plan AS pl
INNER JOIN sys.query_store_query AS qry
ON pl.query_id = qry.query_id
INNER JOIN sys.query_store_query_text AS txt
ON qry.query_text_id = txt.query_text_id
WHERE pl.is_forced_plan=1;
After you identify the query_id and plan_id that you want to unforce, use the following example to unforce the plan:
EXEC sp_query_store_unforce_plan @query_id = 3, @plan_id = 55
or
EXEC sp_query_store_unforce_plan 3, 55;