1
1
/* *******************************************************
2
2
* SETUP - clear everything
3
3
********************************************************/
4
- EXEC [dbo].[initialize]
5
-
4
+ ALTER DATABASE current SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF );
5
+ EXEC dbo . initialize ;
6
6
7
7
/* *******************************************************
8
8
* PART I
9
- * Plan regression identification.
9
+ * Plan regression identification & manual tuning
10
10
********************************************************/
11
11
12
- -- 1. Start workload - execute procedure 30-300 times:
13
- begin
14
- declare @packagetypeid int = 7 ;
15
- exec dbo .report @packagetypeid
16
- end
17
- go 300
18
- -- Queries should be fast
19
- -- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Hash Aggregate)
12
+ -- Execute the query and include "Actual execution plan" in SSMS and show the plan - it should have Hash Match (Aggregate) operator with Columnstore Index Scan
13
+ EXEC sp_executesql N' select avg([UnitPrice]*[Quantity])
14
+ from Sales.OrderLines
15
+ where PackageTypeID = @packagetypeid' , N ' @packagetypeid int' , @packagetypeid = 7 ;
16
+ GO 60
17
+ -- 1. Execute this query 45-300 times to setup the baseline.
18
+ -- If you have QUERY_STORE CAPTURE_POLICY=AUTO increase number in GO <number> to at least 60
20
19
21
20
22
- -- 2. Execute procedure that causes plan regression
23
- -- Optionally, include "Actual execution plan" in SSMS and show the plan ( it should have Stream Aggregate)
24
- exec dbo .regression
21
+ -- 2. Execute the procedure that causes plan regression
22
+ -- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Stream Aggregate, Index Seek & Nested Loops
23
+ EXEC dbo .regression ;
25
24
26
25
27
- -- 3. Start workload again - verify that is slower.
28
- begin
29
- declare @packagetypeid int = 7 ;
30
- exec dbo .report @packagetypeid
31
- end
26
+ -- 3. Start the workload again - verify that is slower.
27
+ EXEC sp_executesql N' select avg([UnitPrice]*[Quantity])
28
+ from Sales.OrderLines
29
+ where PackageTypeID = @packagetypeid' , N ' @packagetypeid int' , @packagetypeid = 7 ;
32
30
go 20
33
- -- Optionally, include "Actual execution plan" in SSMS and show the plan ( it should have Stream Aggregate)
31
+ -- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Stream Aggregate with Non-clustered index seek.
34
32
35
- -- 4. Find recommendation recommended by database:
36
- SELECT planForceDetails .query_id , reason, score,
37
- JSON_VALUE(details, ' $.implementationDetails.script' ) [correction script],
38
- planForceDetails.[new plan_id], planForceDetails.[recommended plan_id]
39
- FROM sys .dm_db_tuning_recommendations
40
- CROSS APPLY OPENJSON (Details, ' $.planForceDetails' )
41
- WITH ( [query_id] int ' $.queryId' ,
42
- [new plan_id] int ' $.regressedPlanId' ,
43
- [recommended plan_id] int ' $.recommendedPlanId'
44
- ) as planForceDetails;
33
+ -- 4. Find a recommendation that can fix this issue:
34
+ SELECT reason, score,
35
+ script = JSON_VALUE(details, ' $.implementationDetails.script' )
36
+ FROM sys .dm_db_tuning_recommendations ;
45
37
38
+ -- 4.1. Optionally get more detailed information about the regression and recommendation.
39
+ SELECT reason, score,
40
+ script = JSON_VALUE(details, ' $.implementationDetails.script' ),
41
+ planForceDetails.[query_id],
42
+ planForceDetails.[new plan_id],
43
+ planForceDetails.[recommended plan_id],
44
+ estimated_gain = (regressedPlanExecutionCount+ recommendedPlanExecutionCount)* (regressedPlanCpuTimeAverage- recommendedPlanCpuTimeAverage)/ 1000000 ,
45
+ error_prone = IIF (regressedPlanErrorCount> recommendedPlanErrorCount, ' YES' ,' NO' )
46
+ FROM sys .dm_db_tuning_recommendations
47
+ CROSS APPLY OPENJSON (Details, ' $.planForceDetails' )
48
+ WITH ( [query_id] int ' $.queryId' ,
49
+ [new plan_id] int ' $.regressedPlanId' ,
50
+ [recommended plan_id] int ' $.recommendedPlanId' ,
51
+ regressedPlanErrorCount int ,
52
+ recommendedPlanErrorCount int ,
53
+ regressedPlanExecutionCount int ,
54
+ regressedPlanCpuTimeAverage float ,
55
+ recommendedPlanExecutionCount int ,
56
+ recommendedPlanCpuTimeAverage float ) as planForceDetails;
57
+ -- IMPORTANT NOTE: check is estimated_gain > 10.
58
+ -- If estimated_gain < 10 THEN FLGP=ON will not automatically force the plan!!!
59
+ -- In that case increase the number of executions in initial workload.
60
+ -- Make sure that SQL Engine uses columnstore in original plan and nonclustered index in regressed plan.
46
61
47
62
-- Note: User can apply script and force the recommended plan to correct the error.
48
63
<< Insert T- SQL from the script column here and execute the script>>
49
64
-- e.g.: exec sp_query_store_force_plan @query_id = 3, @plan_id = 1
50
65
51
- -- 5. Start workload again - verify that is faster.
52
- begin
53
- declare @packagetypeid int = 7 ;
54
- exec dbo .report @packagetypeid
55
- end
56
- go 20
57
- -- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Hash Aggregate again)
66
+ -- 5. Execute the query again - verify that it is faster.
67
+ EXEC sp_executesql N' select avg([UnitPrice]*[Quantity])
68
+ from Sales.OrderLines
69
+ where PackageTypeID = @packagetypeid' , N ' @packagetypeid int' , @packagetypeid = 7 ;
70
+ GO 20
71
+ -- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Hash Aggregate & Columnstore again
58
72
59
73
60
74
-- In part II will be shown better approach - automatic tuning.
@@ -74,29 +88,26 @@ ALTER DATABASE current
74
88
SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = ON );
75
89
76
90
-- Verify that actual state on FLGP is ON:
77
- SELECT name , desired_state_desc, actual_state_desc, reason_desc
78
- FROM sys .database_automatic_tuning_options ;
79
-
91
+ SELECT name , actual_state_desc, status = IIF (desired_state_desc <> actual_state_desc, reason_desc, ' Status:OK' )
92
+ FROM sys .database_automatic_tuning_options
93
+ WHERE name = ' FORCE_LAST_GOOD_PLAN' ;
80
94
81
95
-- 1. Start workload - execute procedure 30-300 times like in the phase I
82
- begin
83
- declare @packagetypeid int = 7 ;
84
- exec dbo .report @packagetypeid
85
- end
86
- go 300
96
+ EXEC sp_executesql N' select avg([UnitPrice]*[Quantity])
97
+ from Sales.OrderLines
98
+ where PackageTypeID = @packagetypeid' , N ' @packagetypeid int' , @packagetypeid = 7 ;
99
+ GO 60
87
100
88
- -- 2. Execute the procedure that causes plan regression
101
+ -- 2. Execute the procedure that causes the plan regression
89
102
exec dbo .regression ;
90
103
91
- -- 3. Start workload again - verify that it is slower.
92
- begin
93
- declare @packagetypeid int = 7 ;
94
- exec dbo .report @packagetypeid;
95
- end
96
- go 20
104
+ -- 3. Start the workload again - verify that it is slower.
105
+ EXEC sp_executesql N' select avg([UnitPrice]*[Quantity])
106
+ from Sales.OrderLines
107
+ where PackageTypeID = @packagetypeid' , N ' @packagetypeid int' , @packagetypeid = 7 ;
108
+ go 30
97
109
98
- -- 4. Find recommendation that returns query perf regression
99
- -- and check is it in Verifying state:
110
+ -- 4. Find a recommendation and check is it in "Verifying" or "Success" state:
100
111
SELECT reason, score,
101
112
JSON_VALUE(state , ' $.currentValue' ) state ,
102
113
JSON_VALUE(state , ' $.reason' ) state_transition_reason,
@@ -110,11 +121,11 @@ FROM sys.dm_db_tuning_recommendations
110
121
) as planForceDetails;
111
122
112
123
113
- -- 5. Wait until recommendation is applied and start workload again - verify that it is faster.
114
- begin
115
- declare @packagetypeid int = 7 ;
116
- exec dbo .report @packagetypeid
117
- end
118
- go 30
124
+ -- 5. Recommendation is in "Verifying" state, but the last good plan is forced, so the query will be faster:
125
+ EXEC sp_executesql N' select avg([UnitPrice]*[Quantity])
126
+ from Sales.OrderLines
127
+ where PackageTypeID = @packagetypeid' , N ' @packagetypeid int' , @packagetypeid = 7 ;
128
+
129
+
130
+ -- Open Query Store/"Top Resource Consuming Queries" dialog in SSMS and show that the better plan is forced.
119
131
120
- -- Open Query Store/"Top Resource Consuming Queries" dialog in SSMS and show that better plan is forced.
0 commit comments