Skip to content

Commit 65639eb

Browse files
committed
sp_WhatsupQueryStore v1.2
1 parent 89f6b77 commit 65639eb

1 file changed

Lines changed: 150 additions & 82 deletions

File tree

sp_WhatsupQueryStore.sql

Lines changed: 150 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/*********************************************************************************************
2-
sp_WhatsupQueryStore v1.1
3-
(C) Enrico van de Laar (@evdlaar)
2+
sp_WhatsupQueryStore v1.2
3+
(C) Enrico van de Laar (Twitter: @evdlaar)
4+
https://github.com/Evdlaar/sp_WhatsupQueryStore
45
5-
Feedback: mailto:enrico@dotnine.net
6+
Feedback: mailto:enrico@dotnine.net
67
78
License:
89
This script is free to download and use for personal, educational, and internal
@@ -32,13 +33,17 @@ CREATE PROCEDURE sp_WhatsupQueryStore
3233
@dbname VARCHAR(75),
3334
@timewindow VARCHAR(4) = 1,
3435
@topqueries VARCHAR(4) = 25,
35-
@return_store_config INT = 1,
36-
@return_forced_plans INT = 1,
37-
@return_top_duration INT = 1,
38-
@return_top_cpu INT = 1,
39-
@return_top_log_read INT = 1,
40-
@return_top_log_write INT = 1,
41-
@return_top_phys_read INT = 1
36+
@return_store_config INT = 0,
37+
@return_forced_plans INT = 0,
38+
@return_multiple_plans INT = 0,
39+
@return_top_executed INT = 0,
40+
@return_top_duration INT = 0,
41+
@return_top_cpu INT = 0,
42+
@return_top_log_read INT = 0,
43+
@return_top_log_write INT = 0,
44+
@return_top_phys_read INT = 0,
45+
@return_all INT = 0,
46+
@show_query_hints INT = 0
4247

4348
AS
4449

@@ -75,7 +80,7 @@ ELSE
7580
-- Now that we detected that the Query Store is enabled on the target database
7681
-- we can start grabbing information from it.
7782

78-
IF @return_store_config = 1
83+
IF @return_store_config = 1 OR @return_all = 1
7984

8085
BEGIN
8186

@@ -113,7 +118,7 @@ ELSE
113118
Forced Query Store plans
114119
*/
115120

116-
IF @return_forced_plans = 1
121+
IF @return_forced_plans = 1 OR @return_all = 1
117122
BEGIN
118123

119124
SELECT 'Forced Query Store Execution Plans' AS 'Info'
@@ -146,85 +151,148 @@ ELSE
146151
Queries with multiple execution plans
147152
*/
148153

149-
SELECT 'Queries with multiple plans in the last ' + @timewindow + ' hour(s)' AS 'Info'
150-
151-
DECLARE @sql_qs_multiple_plans NVARCHAR(MAX)
152-
153-
SET @sql_qs_multiple_plans =
154-
N'WITH CTE_QS_Multiple_Plans (query_id, plan_count)
155-
AS
156-
(
157-
SELECT
158-
qsp.query_id,
159-
COUNT(qsp.plan_id)
160-
FROM ' + @dbname + '.sys.query_store_plan qsp WITH (NOLOCK)
161-
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
162-
GROUP BY query_id HAVING COUNT(plan_id) > 1
163-
)
164-
165-
SELECT
166-
cte.query_id AS ''Query ID'',
167-
CAST(qsp.query_plan AS XML) AS ''Execution Plan''
168-
FROM CTE_QS_Multiple_Plans cte
169-
INNER JOIN ' + @dbname + '.sys.query_store_plan qsp
170-
ON cte.query_id = qsp.query_id
171-
INNER JOIN ' + @dbname + '.sys.query_store_query qsq WITH (NOLOCK)
172-
ON qsp.query_id = qsq.query_id
173-
INNER JOIN ' + @dbname + '.sys.query_store_query_text qsqt WITH (NOLOCK)
174-
ON qsq.query_text_id = qsqt.query_text_id
175-
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
176-
ORDER BY cte.query_id ASC
177-
'
178-
179-
EXEC sp_executesql @sql_qs_multiple_plans
154+
IF @return_multiple_plans = 1 OR @return_all = 1
155+
156+
BEGIN
157+
158+
SELECT 'Queries with multiple plans in the last ' + @timewindow + ' hour(s)' AS 'Info'
159+
160+
DECLARE @sql_qs_multiple_plans NVARCHAR(MAX)
161+
162+
IF @show_query_hints = 0
163+
164+
BEGIN
165+
166+
SET @sql_qs_multiple_plans =
167+
N'WITH CTE_QS_Multiple_Plans (query_id, plan_count)
168+
AS
169+
(
170+
SELECT
171+
qsp.query_id,
172+
COUNT(qsp.plan_id)
173+
FROM ' + @dbname + '.sys.query_store_plan qsp WITH (NOLOCK)
174+
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
175+
GROUP BY query_id HAVING COUNT(plan_id) > 1
176+
)
177+
178+
SELECT
179+
cte.query_id AS ''Query ID'',
180+
qsp.plan_id AS ''Plan ID'',
181+
CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS ''Last Execution Time'',
182+
qsqt.query_sql_text AS ''Query Text'',
183+
qsp.engine_version AS ''Engine Version'',
184+
qsp.[compatibility_level] AS ''Compatibility Level'',
185+
CAST(qsp.query_plan AS XML) AS ''Execution Plan''
186+
FROM CTE_QS_Multiple_Plans cte
187+
INNER JOIN ' + @dbname + '.sys.query_store_plan qsp
188+
ON cte.query_id = qsp.query_id
189+
INNER JOIN ' + @dbname + '.sys.query_store_query qsq WITH (NOLOCK)
190+
ON qsp.query_id = qsq.query_id
191+
INNER JOIN ' + @dbname + '.sys.query_store_query_text qsqt WITH (NOLOCK)
192+
ON qsq.query_text_id = qsqt.query_text_id
193+
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
194+
ORDER BY cte.query_id ASC
195+
'
196+
197+
EXEC sp_executesql @sql_qs_multiple_plans
198+
199+
END
200+
201+
IF @show_query_hints = 1
202+
203+
BEGIN
204+
205+
SET @sql_qs_multiple_plans =
206+
N'WITH CTE_QS_Multiple_Plans (query_id, plan_count)
207+
AS
208+
(
209+
SELECT
210+
qsp.query_id,
211+
COUNT(qsp.plan_id)
212+
FROM ' + @dbname + '.sys.query_store_plan qsp WITH (NOLOCK)
213+
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
214+
GROUP BY query_id HAVING COUNT(plan_id) > 1
215+
)
216+
217+
SELECT
218+
cte.query_id AS ''Query ID'',
219+
qsp.plan_id AS ''Plan ID'',
220+
CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS ''Last Execution Time'',
221+
qsqt.query_sql_text AS ''Query Text'',
222+
qsp.engine_version AS ''Engine Version'',
223+
qsp.[compatibility_level] AS ''Compatibility Level'',
224+
CAST(qsp.query_plan AS XML) AS ''Execution Plan'',
225+
CAST(''-- Force Execution Plan '' + CAST(qsp.plan_id AS varchar) + '' for Query '' + CAST(cte.query_id AS varchar) + '' through the Query Store 
 EXEC sp_query_store_force_plan '' + CAST(cte.query_id AS varchar) + '', '' + CAST(qsp.plan_id AS varchar) + '''' AS XML) AS ''Force Plan''
226+
FROM CTE_QS_Multiple_Plans cte
227+
INNER JOIN ' + @dbname + '.sys.query_store_plan qsp
228+
ON cte.query_id = qsp.query_id
229+
INNER JOIN ' + @dbname + '.sys.query_store_query qsq WITH (NOLOCK)
230+
ON qsp.query_id = qsq.query_id
231+
INNER JOIN ' + @dbname + '.sys.query_store_query_text qsqt WITH (NOLOCK)
232+
ON qsq.query_text_id = qsqt.query_text_id
233+
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsp.last_execution_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
234+
ORDER BY cte.query_id ASC
235+
'
236+
237+
EXEC sp_executesql @sql_qs_multiple_plans
238+
239+
END
240+
241+
END
180242

181243
/*
182244
SECTION 4
183245
Top queries based on execution amount
184246
*/
185247

186-
SELECT 'Most executed queries in the last ' + @timewindow + ' hour(s)' AS 'Info'
187-
188-
DECLARE @sql_qs_top_nr_executions NVARCHAR(MAX)
189-
190-
SET @sql_qs_top_nr_executions =
191-
N'WITH CTE_QS_Top_Executions (plan_id, exec_count)
192-
AS
193-
(
194-
SELECT TOP ' + @topqueries + '
195-
qsrs.plan_id,
196-
SUM(qsrs.count_executions)
197-
FROM ' + @dbname + '.sys.query_store_runtime_stats qsrs WITH (NOLOCK)
198-
INNER JOIN ' + @dbname + '.sys.query_store_runtime_stats_interval qsrsi WITH (NOLOCK)
199-
ON qsrs.runtime_stats_interval_id = qsrsi.runtime_stats_interval_id
200-
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsrsi.end_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
201-
GROUP BY qsrs.plan_id
202-
ORDER BY SUM(qsrs.count_executions) DESC
203-
)
204-
205-
SELECT
206-
cte.plan_id AS ''Plan ID'',
207-
qsp.query_id AS ''Query ID'',
208-
qsqt.query_sql_text AS ''Statement'',
209-
CAST(qsp.query_plan AS XML) AS ''Execution Plan'',
210-
cte.exec_count AS ''Execution count''
211-
FROM CTE_QS_Top_Executions cte
212-
INNER JOIN ' + @dbname + '.sys.query_store_plan qsp WITH (NOLOCK)
213-
ON cte.plan_id = qsp.plan_id
214-
INNER JOIN ' + @dbname + '.sys.query_store_query qsq WITH (NOLOCK)
215-
ON qsp.query_id = qsq.query_id
216-
INNER JOIN ' + @dbname + '.sys.query_store_query_text qsqt WITH (NOLOCK)
217-
ON qsq.query_text_id = qsqt.query_text_id
218-
'
248+
IF @return_top_executed = 1 OR @return_all = 1
249+
250+
BEGIN
251+
252+
SELECT 'Most executed queries in the last ' + @timewindow + ' hour(s)' AS 'Info'
253+
254+
DECLARE @sql_qs_top_nr_executions NVARCHAR(MAX)
255+
256+
SET @sql_qs_top_nr_executions =
257+
N'WITH CTE_QS_Top_Executions (plan_id, exec_count)
258+
AS
259+
(
260+
SELECT TOP ' + @topqueries + '
261+
qsrs.plan_id,
262+
SUM(qsrs.count_executions)
263+
FROM ' + @dbname + '.sys.query_store_runtime_stats qsrs WITH (NOLOCK)
264+
INNER JOIN ' + @dbname + '.sys.query_store_runtime_stats_interval qsrsi WITH (NOLOCK)
265+
ON qsrs.runtime_stats_interval_id = qsrsi.runtime_stats_interval_id
266+
WHERE CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, qsrsi.end_time), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) >= DATEADD(hour, -' + @timewindow + ', getdate())
267+
GROUP BY qsrs.plan_id
268+
ORDER BY SUM(qsrs.count_executions) DESC
269+
)
270+
271+
SELECT
272+
cte.plan_id AS ''Plan ID'',
273+
qsp.query_id AS ''Query ID'',
274+
qsqt.query_sql_text AS ''Statement'',
275+
CAST(qsp.query_plan AS XML) AS ''Execution Plan'',
276+
cte.exec_count AS ''Execution count''
277+
FROM CTE_QS_Top_Executions cte
278+
INNER JOIN ' + @dbname + '.sys.query_store_plan qsp WITH (NOLOCK)
279+
ON cte.plan_id = qsp.plan_id
280+
INNER JOIN ' + @dbname + '.sys.query_store_query qsq WITH (NOLOCK)
281+
ON qsp.query_id = qsq.query_id
282+
INNER JOIN ' + @dbname + '.sys.query_store_query_text qsqt WITH (NOLOCK)
283+
ON qsq.query_text_id = qsqt.query_text_id
284+
'
219285

220-
EXEC sp_executesql @sql_qs_top_nr_executions
286+
EXEC sp_executesql @sql_qs_top_nr_executions
287+
288+
END
221289

222290
/*
223291
SECTION 5
224292
Top queries based on average duration
225293
*/
226294

227-
IF @return_top_duration = 1
295+
IF @return_top_duration = 1 OR @return_all = 1
228296

229297
BEGIN
230298

@@ -277,7 +345,7 @@ ELSE
277345
Top queries based on average CPU Time
278346
*/
279347

280-
IF @return_top_cpu = 1
348+
IF @return_top_cpu = 1 OR @return_all = 1
281349

282350
BEGIN
283351

@@ -330,7 +398,7 @@ ELSE
330398
Top queries based on average logical IO reads
331399
*/
332400

333-
IF @return_top_log_read = 1
401+
IF @return_top_log_read = 1 OR @return_all = 1
334402

335403
BEGIN
336404

@@ -383,7 +451,7 @@ ELSE
383451
Top queries based on average logical IO writes
384452
*/
385453

386-
IF @return_top_log_write = 1
454+
IF @return_top_log_write = 1 OR @return_all = 1
387455

388456
BEGIN
389457

@@ -436,7 +504,7 @@ ELSE
436504
Top queries based on average physical IO reads
437505
*/
438506

439-
IF @return_top_phys_read = 1
507+
IF @return_top_phys_read = 1 OR @return_all = 1
440508

441509
BEGIN
442510

0 commit comments

Comments
 (0)