Skip to content

Commit dbbf312

Browse files
committed
Adds same functionality to BQS
YEEHAW
1 parent fd5bd01 commit dbbf312

File tree

1 file changed

+197
-22
lines changed

1 file changed

+197
-22
lines changed

sp_BlitzQueryStore.sql

Lines changed: 197 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ OPTION (RECOMPILE);
9595
SELECT @log_size_mb = AVG(((mf.size * 8) / 1024.))
9696
FROM sys.master_files AS mf
9797
WHERE mf.database_id = DB_ID(@DatabaseName)
98-
AND mf.type_desc = 'LOG'
98+
AND mf.type_desc = 'LOG';
9999

100100
/*Grab avg tempdb file size*/
101101
SELECT @avg_tempdb_data_file = AVG(((mf.size * 8) / 1024.))
102102
FROM sys.master_files AS mf
103103
WHERE mf.database_id = DB_ID('tempdb')
104-
AND mf.type_desc = 'ROWS'
104+
AND mf.type_desc = 'ROWS';
105105

106106

107107
/*Help section*/
@@ -173,8 +173,8 @@ IF ( (SELECT SERVERPROPERTY ('EDITION')) = 'SQL Azure' )
173173
SELECT @msg = N'Sorry, sp_BlitzQueryStore doesn''t work on Azure Data Warehouse, or Azure Databases with DB compatibility < 130.' + REPLICATE(CHAR(13), 7933);
174174
PRINT @msg;
175175
RETURN;
176-
END
177-
END
176+
END;
177+
END;
178178
ELSE IF ( (SELECT PARSENAME(CONVERT(NVARCHAR(128), SERVERPROPERTY ('PRODUCTVERSION')), 4) ) < 13 )
179179
BEGIN
180180
SELECT @msg = N'Sorry, sp_BlitzQueryStore doesn''t work on versions of SQL prior to 2016.' + REPLICATE(CHAR(13), 7933);
@@ -200,7 +200,7 @@ IF ( SELECT COUNT(*)
200200
RAISERROR('Checking database validity', 0, 1) WITH NOWAIT;
201201

202202
IF (@is_azure_db = 1)
203-
SET @DatabaseName = DB_NAME()
203+
SET @DatabaseName = DB_NAME();
204204
ELSE
205205
BEGIN
206206

@@ -251,11 +251,11 @@ END;
251251

252252
/*Check database compat level*/
253253

254-
RAISERROR('Checking database compatibility level', 0, 1) WITH NOWAIT
254+
RAISERROR('Checking database compatibility level', 0, 1) WITH NOWAIT;
255255

256256
SELECT @compatibility_level = d.compatibility_level
257257
FROM sys.databases AS d
258-
WHERE d.name = @DatabaseName
258+
WHERE d.name = @DatabaseName;
259259

260260
RAISERROR('The @DatabaseName you specified ([%s])is running in compatibility level ([%d]).', 0, 1, @DatabaseName, @compatibility_level) WITH NOWAIT;
261261

@@ -610,6 +610,8 @@ CREATE TABLE #working_warnings
610610
is_big_log BIT,
611611
is_big_tempdb BIT,
612612
is_paul_white_electric BIT,
613+
implicit_conversion_info XML,
614+
cached_execution_parameters XML,
613615
warnings NVARCHAR(4000)
614616
INDEX ww_ix_ids CLUSTERED (plan_id, query_id, query_hash, sql_handle)
615617
);
@@ -757,7 +759,22 @@ CREATE TABLE #warning_results
757759
FindingsGroup NVARCHAR(50),
758760
Finding NVARCHAR(200),
759761
URL NVARCHAR(200),
760-
Details NVARCHAR(4000)
762+
Details NVARCHAR(4000)
763+
);
764+
765+
DROP TABLE IF EXISTS #stored_proc_info;
766+
767+
CREATE TABLE #stored_proc_info
768+
(
769+
sql_handle VARBINARY(64),
770+
query_hash BINARY(8),
771+
variable_name NVARCHAR(128),
772+
variable_datatype NVARCHAR(128),
773+
compile_time_value NVARCHAR(128),
774+
proc_name NVARCHAR(300),
775+
column_name NVARCHAR(128),
776+
converted_to NVARCHAR(128),
777+
INDEX tf_ix_ids CLUSTERED (sql_handle, query_hash)
761778
);
762779

763780
/*Sets up WHERE clause that gets used quite a bit*/
@@ -878,8 +895,8 @@ IF (@ExportToExcel = 1 OR @SkipXML = 1)
878895
IF @StoredProcName IS NOT NULL
879896
BEGIN
880897

881-
DECLARE @sql NVARCHAR(MAX)
882-
DECLARE @out INT
898+
DECLARE @sql NVARCHAR(MAX);
899+
DECLARE @out INT;
883900
DECLARE @proc_params NVARCHAR(MAX) = N'@sp_StartDate DATETIME2, @sp_EndDate DATETIME2, @sp_MinimumExecutionCount INT, @sp_MinDuration INT, @sp_StoredProcName NVARCHAR(128), @sp_PlanIdFilter INT, @sp_QueryIdFilter INT, @i_out INT OUTPUT';
884901

885902

@@ -904,16 +921,16 @@ IF @StoredProcName IS NOT NULL
904921
BEGIN
905922

906923
SET @msg = N'We couldn''t find the Stored Procedure ' + QUOTENAME(@StoredProcName) + N' in the Query Store views for ' + QUOTENAME(@DatabaseName) + N' between ' + CONVERT(NVARCHAR(30), ISNULL(@StartDate, DATEADD(DAY, -7, DATEDIFF(DAY, 0, SYSDATETIME() ))) ) + N' and ' + CONVERT(NVARCHAR(30), ISNULL(@EndDate, SYSDATETIME())) +
907-
'. Try removing schema prefixes or adjusting dates. If it was executed from a different database context, try searching there instead.'
924+
'. Try removing schema prefixes or adjusting dates. If it was executed from a different database context, try searching there instead.';
908925
RAISERROR(@msg, 0, 1) WITH NOWAIT;
909926

910-
SELECT @msg AS [Blue Flowers, Blue Flowers, Blue Flowers]
927+
SELECT @msg AS [Blue Flowers, Blue Flowers, Blue Flowers];
911928

912929
RETURN;
913930

914-
END
931+
END;
915932

916-
END
933+
END;
917934

918935

919936

@@ -1460,7 +1477,7 @@ SELECT ' + QUOTENAME(@DatabaseName, '''') + N' AS database_name, wp.plan_id, wp.
14601477
((qsrs.last_query_max_used_memory * 8 ) / 1024.),
14611478
((qsrs.min_query_max_used_memory * 8 ) / 1024.),
14621479
((qsrs.max_query_max_used_memory * 8 ) / 1024.),
1463-
qsrs.avg_rowcount, qsrs.last_rowcount, qsrs.min_rowcount, qsrs.max_rowcount,'
1480+
qsrs.avg_rowcount, qsrs.last_rowcount, qsrs.min_rowcount, qsrs.max_rowcount,';
14641481

14651482
IF @new_columns = 1
14661483
BEGIN
@@ -1474,8 +1491,8 @@ SELECT ' + QUOTENAME(@DatabaseName, '''') + N' AS database_name, wp.plan_id, wp.
14741491
((qsrs.last_tempdb_space_used * 8 ) / 1024.),
14751492
((qsrs.min_tempdb_space_used * 8 ) / 1024.),
14761493
((qsrs.max_tempdb_space_used * 8 ) / 1024.)
1477-
'
1478-
END
1494+
';
1495+
END;
14791496
IF @new_columns = 0
14801497
BEGIN
14811498
SET @sql_select += N'
@@ -1491,8 +1508,8 @@ SELECT ' + QUOTENAME(@DatabaseName, '''') + N' AS database_name, wp.plan_id, wp.
14911508
NULL,
14921509
NULL,
14931510
NULL
1494-
'
1495-
END
1511+
';
1512+
END;
14961513
SET @sql_select +=
14971514
N'FROM #working_plans AS wp
14981515
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.query_store_query AS qsq
@@ -2153,7 +2170,7 @@ SELECT DISTINCT
21532170
c.n.value('(/p:StmtSimple/@StatementEstRows)[1]', 'FLOAT') AS estimated_rows
21542171
FROM #statements AS s
21552172
CROSS APPLY s.statement.nodes('/p:StmtSimple') AS c(n)
2156-
WHERE c.n.exist('/p:StmtSimple[@StatementEstRows > 0]') = 1
2173+
WHERE c.n.exist('/p:StmtSimple[@StatementEstRows > 0]') = 1;
21572174

21582175
UPDATE b
21592176
SET b.estimated_rows = er.estimated_rows
@@ -2652,6 +2669,159 @@ JOIN is_paul_white_electric ipwe
26522669
ON ipwe.sql_handle = b.sql_handle
26532670
OPTION (RECOMPILE);
26542671

2672+
IF EXISTS ( SELECT 1
2673+
FROM #working_warnings AS ww
2674+
WHERE ww.implicit_conversions = 1
2675+
OR ww.proc_or_function_name <> N'Statement')
2676+
BEGIN
2677+
2678+
RAISERROR(N'Getting information about implicit conversions and stored proc parameters', 0, 1) WITH NOWAIT;
2679+
2680+
WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p )
2681+
, variables_types
2682+
AS (
2683+
2684+
--WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p )
2685+
SELECT
2686+
qp.query_hash,
2687+
qp.sql_handle,
2688+
b.proc_or_function_name AS proc_name,
2689+
q.n.value('@Column', 'NVARCHAR(128)') AS variable_name,
2690+
q.n.value('@ParameterDataType', 'NVARCHAR(128)') AS variable_datatype,
2691+
q.n.value('@ParameterCompiledValue', 'NVARCHAR(1000)') AS compile_time_value
2692+
FROM #query_plan AS qp
2693+
JOIN #working_warnings AS b
2694+
ON b.query_hash = qp.query_hash
2695+
CROSS APPLY qp.query_plan.nodes('//p:QueryPlan/p:ParameterList/p:ColumnReference') AS q(n)
2696+
WHERE b.implicit_conversions = 1 ),
2697+
convert_implicit
2698+
AS (
2699+
--WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p )
2700+
SELECT
2701+
qp.query_hash,
2702+
qp.sql_handle,
2703+
b.proc_or_function_name AS proc_name,
2704+
qq.c.value('@Expression', 'NVARCHAR(128)') AS expression,
2705+
SUBSTRING(
2706+
qq.c.value('@Expression', 'NVARCHAR(128)'), --Original Expression
2707+
CHARINDEX('@', qq.c.value('@Expression', 'NVARCHAR(128)')), --Charindex of @+1
2708+
CHARINDEX(']',
2709+
qq.c.value('@Expression', 'NVARCHAR(128)'), --Charindex of end bracket
2710+
CHARINDEX('@', qq.c.value('@Expression', 'NVARCHAR(128)')) + 1 --Starting at the Charindex of the @ +1
2711+
) - CHARINDEX('@', qq.c.value('@Expression', 'NVARCHAR(128)'))) AS variable_name,
2712+
SUBSTRING(
2713+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Original Expression
2714+
CHARINDEX('].[', qq.c.value('@Expression', 'NVARCHAR(128)')) + 3, --Charindex of ].[ + 3
2715+
CHARINDEX(']',
2716+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Charindex of end bracket
2717+
CHARINDEX('].[', qq.c.value('@Expression', 'NVARCHAR(128)')) + 3 --Starting at the Charindex of ].[ + 3
2718+
) - CHARINDEX('].[', qq.c.value('@Expression', 'NVARCHAR(128)')) - 3) AS column_name,
2719+
SUBSTRING(
2720+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Original Expression
2721+
CHARINDEX('(', qq.c.value('@Expression', 'NVARCHAR(128)')) + 1, --Charindex of ( + 1
2722+
CHARINDEX(',',
2723+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Charindex of comma
2724+
CHARINDEX('(', qq.c.value('@Expression', 'NVARCHAR(128)')) + 1 --Starting at the Charindex of ( + 1
2725+
) - CHARINDEX('(', qq.c.value('@Expression', 'NVARCHAR(128)')) - 1) AS converted_to
2726+
FROM #query_plan AS qp
2727+
JOIN #working_warnings AS b
2728+
ON b.query_hash = qp.query_hash
2729+
CROSS APPLY qp.query_plan.nodes('//p:QueryPlan/p:Warnings/p:PlanAffectingConvert') AS qq(c)
2730+
WHERE qq.c.exist('@ConvertIssue[.="Seek Plan"]') = 1
2731+
AND qp.query_hash IS NOT NULL
2732+
AND b.implicit_conversions = 1 )
2733+
INSERT #stored_proc_info ( query_hash, sql_handle, variable_name, variable_datatype, compile_time_value, proc_name, column_name, converted_to )
2734+
SELECT DISTINCT
2735+
COALESCE(vt.query_hash, ci.query_hash) AS query_hash,
2736+
COALESCE(vt.sql_handle, ci.sql_handle) AS sql_handle,
2737+
COALESCE(vt.variable_name, ci.variable_name) AS variable_name,
2738+
COALESCE(vt.variable_datatype, ci.converted_to) AS variable_datatype,
2739+
COALESCE(vt.compile_time_value, '*declared in proc*') AS compile_time_value,
2740+
COALESCE(vt.proc_name, ci.proc_name) AS proc_name,
2741+
ci.column_name,
2742+
ci.converted_to
2743+
FROM variables_types AS vt
2744+
RIGHT JOIN convert_implicit AS ci
2745+
ON (ci.variable_name = vt.variable_name
2746+
AND ci.query_hash = vt.query_hash)
2747+
OPTION(RECOMPILE);
2748+
2749+
WITH precheck AS (
2750+
SELECT
2751+
spi.sql_handle,
2752+
spi.proc_name,
2753+
CONVERT(XML,
2754+
N'<?ClickMe -- '
2755+
+ @cr + @lf
2756+
+ N'The '
2757+
+ CASE WHEN spi.proc_name <> 'Statement'
2758+
THEN N'stored procedure ' + spi.proc_name
2759+
ELSE N'Statement'
2760+
END
2761+
+ N' had the following implicit conversions: '
2762+
+ CHAR(10)
2763+
+ STUFF((
2764+
SELECT DISTINCT
2765+
@cr + @lf
2766+
+ N'The variable '
2767+
+ spi2.variable_name
2768+
+ N' has a data type of '
2769+
+ spi2.variable_datatype
2770+
+ N' which caused implicit conversion on the column '
2771+
+ spi2.column_name
2772+
+ CASE WHEN spi2.compile_time_value = '*declared in proc*'
2773+
THEN N' and is a declared variable.'
2774+
ELSE N' and is a parameter of the stored procedure.'
2775+
END
2776+
FROM #stored_proc_info AS spi2
2777+
WHERE spi.sql_handle = spi2.sql_handle
2778+
FOR XML PATH(N''), TYPE).value(N'.[1]', N'NVARCHAR(MAX)'), 1, 1, N'')
2779+
+ CHAR(10)
2780+
+ N' -- ?>'
2781+
) AS implicit_conversion_info,
2782+
CONVERT(XML,
2783+
N'<?ClickMe -- '
2784+
+ @cr + @lf
2785+
+ N'EXEC '
2786+
+ spi.proc_name
2787+
+ N' '
2788+
+ STUFF((
2789+
SELECT DISTINCT N', '
2790+
+ spi2.variable_name
2791+
+ N' = '
2792+
+ CASE WHEN spi2.compile_time_value = 'NULL'
2793+
THEN spi2.compile_time_value
2794+
ELSE QUOTENAME(spi2.compile_time_value, '''')
2795+
END
2796+
FROM #stored_proc_info AS spi2
2797+
WHERE spi.sql_handle = spi2.sql_handle
2798+
AND spi2.proc_name <> 'Statement'
2799+
AND spi2.compile_time_value <> '*declared in proc*'
2800+
FOR XML PATH(N''), TYPE).value(N'.[1]', N'NVARCHAR(MAX)'), 1, 1, N'')
2801+
+ @cr + @lf
2802+
+ N' -- ?>'
2803+
) AS cached_execution_parameters
2804+
FROM #stored_proc_info AS spi
2805+
GROUP BY spi.sql_handle, spi.proc_name
2806+
)
2807+
UPDATE b
2808+
SET b.implicit_conversion_info = pk.implicit_conversion_info,
2809+
b.cached_execution_parameters = pk.cached_execution_parameters
2810+
FROM #working_warnings AS b
2811+
JOIN precheck pk
2812+
ON pk.sql_handle = b.sql_handle
2813+
AND b.implicit_conversions = 1
2814+
OPTION(RECOMPILE);
2815+
2816+
END; --End implicit conversion information gathering
2817+
2818+
UPDATE b
2819+
SET b.implicit_conversion_info = CASE WHEN b.implicit_conversion_info IS NULL THEN '<?NoNeedToClickMe -- N/A --?>' ELSE b.implicit_conversion_info END,
2820+
b.cached_execution_parameters = CASE WHEN b.cached_execution_parameters IS NULL THEN '<?NoNeedToClickMe -- N/A --?>' ELSE b.cached_execution_parameters END
2821+
FROM #working_warnings AS b
2822+
OPTION(RECOMPILE);
2823+
2824+
26552825
RAISERROR(N'General query dispositions: frequent executions, long running, etc.', 0, 1) WITH NOWAIT;
26562826

26572827
WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p)
@@ -2862,9 +3032,10 @@ BEGIN
28623032

28633033
RAISERROR(N'Returning regular results', 0, 1) WITH NOWAIT;
28643034

3035+
28653036
WITH x AS (
28663037
SELECT wpt.database_name, ww.query_cost, wm.plan_id, wm.query_id, wpt.query_sql_text, wm.proc_or_function_name, wpt.query_plan_xml, ww.warnings, wpt.pattern,
2867-
wm.parameter_sniffing_symptoms, wpt.top_three_waits, wm.count_executions, wm.count_compiles, wm.total_cpu_time, wm.avg_cpu_time,
3038+
wm.parameter_sniffing_symptoms, wpt.top_three_waits, ww.implicit_conversion_info, ww.cached_execution_parameters, wm.count_executions, wm.count_compiles, wm.total_cpu_time, wm.avg_cpu_time,
28683039
wm.total_duration, wm.avg_duration, wm.total_logical_io_reads, wm.avg_logical_io_reads,
28693040
wm.total_physical_io_reads, wm.avg_physical_io_reads, wm.total_logical_io_writes, wm.avg_logical_io_writes, wm.total_rowcount, wm.avg_rowcount,
28703041
wm.total_query_max_used_memory, wm.avg_query_max_used_memory, wm.total_tempdb_space_used, wm.avg_tempdb_space_used,
@@ -2893,7 +3064,7 @@ RAISERROR(N'Returning results for failed queries', 0, 1) WITH NOWAIT;
28933064

28943065
WITH x AS (
28953066
SELECT wpt.database_name, ww.query_cost, wm.plan_id, wm.query_id, wpt.query_sql_text, wm.proc_or_function_name, wpt.query_plan_xml, ww.warnings, wpt.pattern,
2896-
wm.parameter_sniffing_symptoms, wpt.last_force_failure_reason_desc, wpt.top_three_waits, wm.count_executions, wm.count_compiles, wm.total_cpu_time, wm.avg_cpu_time,
3067+
wm.parameter_sniffing_symptoms, wpt.last_force_failure_reason_desc, wpt.top_three_waits, ww.implicit_conversion_info, ww.cached_execution_parameters, wm.count_executions, wm.count_compiles, wm.total_cpu_time, wm.avg_cpu_time,
28973068
wm.total_duration, wm.avg_duration, wm.total_logical_io_reads, wm.avg_logical_io_reads,
28983069
wm.total_physical_io_reads, wm.avg_physical_io_reads, wm.total_logical_io_writes, wm.avg_logical_io_writes, wm.total_rowcount, wm.avg_rowcount,
28993070
wm.total_query_max_used_memory, wm.avg_query_max_used_memory, wm.total_tempdb_space_used, wm.avg_tempdb_space_used,
@@ -3955,6 +4126,10 @@ SELECT '#est_rows' AS table_name, *
39554126
FROM #est_rows AS er
39564127
OPTION (RECOMPILE);
39574128

4129+
SELECT '#stored_proc_info' AS table_name, *
4130+
FROM #stored_proc_info AS spi
4131+
OPTION(RECOMPILE);
4132+
39584133
END;
39594134

39604135
END TRY

0 commit comments

Comments
 (0)