Skip to content

Commit 9ec3de9

Browse files
authored
Merge pull request #1131 from BrentOzarULTD/Issue_1129
Adds implicit conversion info to sp_BlitzCache
2 parents 1e3f0a9 + dbbf312 commit 9ec3de9

File tree

2 files changed

+375
-23
lines changed

2 files changed

+375
-23
lines changed

sp_BlitzCache.sql

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ CREATE TABLE ##bou_BlitzCacheProcs (
210210
estimated_rows FLOAT,
211211
is_bad_estimate BIT,
212212
is_paul_white_electric BIT,
213+
implicit_conversion_info XML,
214+
cached_execution_parameters XML,
213215
SetOptions VARCHAR(MAX),
214216
Warnings VARCHAR(MAX)
215217
);
@@ -891,6 +893,8 @@ BEGIN
891893
estimated_rows FLOAT,
892894
is_bad_estimate BIT,
893895
is_paul_white_electric BIT,
896+
implicit_conversion_info XML,
897+
cached_execution_parameters XML,
894898
SetOptions VARCHAR(MAX),
895899
Warnings VARCHAR(MAX)
896900
);
@@ -1017,6 +1021,9 @@ IF OBJECT_ID ('tempdb..#checkversion') IS NOT NULL
10171021
IF OBJECT_ID ('tempdb..#configuration') IS NOT NULL
10181022
DROP TABLE #configuration;
10191023

1024+
IF OBJECT_ID ('tempdb..#stored_proc_info') IS NOT NULL
1025+
DROP TABLE #stored_proc_info;
1026+
10201027
CREATE TABLE #only_query_hashes (
10211028
query_hash BINARY(8)
10221029
);
@@ -1056,6 +1063,20 @@ CREATE TABLE #configuration (
10561063
value DECIMAL(38,0)
10571064
);
10581065

1066+
CREATE TABLE #stored_proc_info
1067+
(
1068+
SPID INT,
1069+
SqlHandle VARBINARY(64),
1070+
QueryHash BINARY(8),
1071+
variable_name NVARCHAR(128),
1072+
variable_datatype NVARCHAR(128),
1073+
compile_time_value NVARCHAR(128),
1074+
proc_name NVARCHAR(300),
1075+
column_name NVARCHAR(128),
1076+
converted_to NVARCHAR(128)
1077+
);
1078+
1079+
10591080
RAISERROR(N'Checking plan cache age', 0, 1) WITH NOWAIT;
10601081
WITH x AS (
10611082
SELECT SUM(CASE WHEN DATEDIFF(HOUR, deqs.creation_time, SYSDATETIME()) <= 24 THEN 1 ELSE 0 END) AS [plans_24],
@@ -1102,7 +1123,6 @@ WHERE cp.usecounts = 1
11021123
OPTION (RECOMPILE) ;
11031124

11041125

1105-
11061126
SET @OnlySqlHandles = LTRIM(RTRIM(@OnlySqlHandles)) ;
11071127
SET @OnlyQueryHashes = LTRIM(RTRIM(@OnlyQueryHashes)) ;
11081128
SET @IgnoreQueryHashes = LTRIM(RTRIM(@IgnoreQueryHashes)) ;
@@ -2826,6 +2846,161 @@ ON ipwe.SqlHandle = b.SqlHandle
28262846
WHERE b.SPID = @@SPID
28272847
OPTION (RECOMPILE);
28282848

2849+
IF EXISTS ( SELECT 1
2850+
FROM ##bou_BlitzCacheProcs AS bbcp
2851+
WHERE bbcp.implicit_conversions = 1
2852+
OR bbcp.QueryType LIKE 'Procedure or Function:%')
2853+
BEGIN
2854+
2855+
RAISERROR(N'Getting information about implicit conversions and stored proc parameters', 0, 1) WITH NOWAIT;
2856+
2857+
WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p )
2858+
, variables_types
2859+
AS (
2860+
2861+
--WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p )
2862+
SELECT
2863+
qp.QueryHash,
2864+
qp.SqlHandle,
2865+
SUBSTRING(b.QueryType, CHARINDEX('[', b.QueryType), LEN(b.QueryType) - CHARINDEX('[', b.QueryType)) AS proc_name,
2866+
q.n.value('@Column', 'NVARCHAR(128)') AS variable_name,
2867+
q.n.value('@ParameterDataType', 'NVARCHAR(128)') AS variable_datatype,
2868+
q.n.value('@ParameterCompiledValue', 'NVARCHAR(1000)') AS compile_time_value
2869+
FROM #query_plan AS qp
2870+
JOIN ##bou_BlitzCacheProcs AS b
2871+
ON b.QueryHash = qp.QueryHash
2872+
CROSS APPLY qp.query_plan.nodes('//p:QueryPlan/p:ParameterList/p:ColumnReference') AS q(n)
2873+
WHERE b.implicit_conversions = 1 ),
2874+
convert_implicit
2875+
AS (
2876+
--WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p )
2877+
SELECT
2878+
qp.QueryHash,
2879+
qp.SqlHandle,
2880+
SUBSTRING(b.QueryType, CHARINDEX('[', b.QueryType), LEN(b.QueryType) - CHARINDEX('[', b.QueryType)) AS proc_name,
2881+
qq.c.value('@Expression', 'NVARCHAR(128)') AS expression,
2882+
SUBSTRING(
2883+
qq.c.value('@Expression', 'NVARCHAR(128)'), --Original Expression
2884+
CHARINDEX('@', qq.c.value('@Expression', 'NVARCHAR(128)')), --Charindex of @+1
2885+
CHARINDEX(']',
2886+
qq.c.value('@Expression', 'NVARCHAR(128)'), --Charindex of end bracket
2887+
CHARINDEX('@', qq.c.value('@Expression', 'NVARCHAR(128)')) + 1 --Starting at the Charindex of the @ +1
2888+
) - CHARINDEX('@', qq.c.value('@Expression', 'NVARCHAR(128)'))) AS variable_name,
2889+
SUBSTRING(
2890+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Original Expression
2891+
CHARINDEX('].[', qq.c.value('@Expression', 'NVARCHAR(128)')) + 3, --Charindex of ].[ + 3
2892+
CHARINDEX(']',
2893+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Charindex of end bracket
2894+
CHARINDEX('].[', qq.c.value('@Expression', 'NVARCHAR(128)')) + 3 --Starting at the Charindex of ].[ + 3
2895+
) - CHARINDEX('].[', qq.c.value('@Expression', 'NVARCHAR(128)')) - 3) AS column_name,
2896+
SUBSTRING(
2897+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Original Expression
2898+
CHARINDEX('(', qq.c.value('@Expression', 'NVARCHAR(128)')) + 1, --Charindex of ( + 1
2899+
CHARINDEX(',',
2900+
qq.c.value('@Expression', 'NVARCHAR(128)'), -- Charindex of comma
2901+
CHARINDEX('(', qq.c.value('@Expression', 'NVARCHAR(128)')) + 1 --Starting at the Charindex of ( + 1
2902+
) - CHARINDEX('(', qq.c.value('@Expression', 'NVARCHAR(128)')) - 1) AS converted_to
2903+
FROM #query_plan AS qp
2904+
JOIN ##bou_BlitzCacheProcs AS b
2905+
ON b.QueryHash = qp.QueryHash
2906+
CROSS APPLY qp.query_plan.nodes('//p:QueryPlan/p:Warnings/p:PlanAffectingConvert') AS qq(c)
2907+
WHERE qq.c.exist('@ConvertIssue[.="Seek Plan"]') = 1
2908+
AND qp.QueryHash IS NOT NULL
2909+
AND b.implicit_conversions = 1 )
2910+
INSERT #stored_proc_info ( SPID, QueryHash, SqlHandle, variable_name, variable_datatype, compile_time_value, proc_name, column_name, converted_to )
2911+
SELECT DISTINCT
2912+
@@SPID AS SPID,
2913+
COALESCE(vt.QueryHash, ci.QueryHash) AS QueryHash,
2914+
COALESCE(vt.SqlHandle, ci.SqlHandle) AS SqlHandle,
2915+
COALESCE(vt.variable_name, ci.variable_name) AS variable_name,
2916+
COALESCE(vt.variable_datatype, ci.converted_to) AS variable_datatype,
2917+
COALESCE(vt.compile_time_value, '*declared in proc*') AS compile_time_value,
2918+
COALESCE(vt.proc_name, ci.proc_name) AS proc_name,
2919+
ci.column_name,
2920+
ci.converted_to
2921+
FROM variables_types AS vt
2922+
RIGHT JOIN convert_implicit AS ci
2923+
ON (ci.variable_name = vt.variable_name
2924+
AND ci.QueryHash = vt.QueryHash)
2925+
OPTION(RECOMPILE);
2926+
2927+
WITH precheck AS (
2928+
SELECT spi.SPID,
2929+
spi.SqlHandle,
2930+
spi.proc_name,
2931+
CONVERT(XML,
2932+
N'<?ClickMe -- '
2933+
+ @nl
2934+
+ N'The '
2935+
+ CASE WHEN spi.proc_name <> 'Statement'
2936+
THEN N'stored procedure ' + spi.proc_name
2937+
ELSE N'Statement'
2938+
END
2939+
+ N' had the following implicit conversions: '
2940+
+ CHAR(10)
2941+
+ STUFF((
2942+
SELECT DISTINCT
2943+
@nl
2944+
+ N'The variable '
2945+
+ spi2.variable_name
2946+
+ N' has a data type of '
2947+
+ spi2.variable_datatype
2948+
+ N' which caused implicit conversion on the column '
2949+
+ spi2.column_name
2950+
+ CASE WHEN spi2.compile_time_value = '*declared in proc*'
2951+
THEN N' and is a declared variable.'
2952+
ELSE N' and is a parameter of the stored procedure.'
2953+
END
2954+
FROM #stored_proc_info AS spi2
2955+
WHERE spi.SqlHandle = spi2.SqlHandle
2956+
FOR XML PATH(N''), TYPE).value(N'.[1]', N'NVARCHAR(MAX)'), 1, 1, N'')
2957+
+ CHAR(10)
2958+
+ N' -- ?>'
2959+
) AS implicit_conversion_info,
2960+
CONVERT(XML,
2961+
N'<?ClickMe -- '
2962+
+ @nl
2963+
+ N'EXEC '
2964+
+ spi.proc_name
2965+
+ N' '
2966+
+ STUFF((
2967+
SELECT DISTINCT N', '
2968+
+ spi2.variable_name
2969+
+ N' = '
2970+
+ CASE WHEN spi2.compile_time_value = 'NULL'
2971+
THEN spi2.compile_time_value
2972+
ELSE QUOTENAME(spi2.compile_time_value, '''')
2973+
END
2974+
FROM #stored_proc_info AS spi2
2975+
WHERE spi.SqlHandle = spi2.SqlHandle
2976+
AND spi2.proc_name <> 'Statement'
2977+
AND spi2.compile_time_value <> '*declared in proc*'
2978+
FOR XML PATH(N''), TYPE).value(N'.[1]', N'NVARCHAR(MAX)'), 1, 1, N'')
2979+
+ @nl
2980+
+ N' -- ?>'
2981+
) AS cached_execution_parameters
2982+
FROM #stored_proc_info AS spi
2983+
GROUP BY spi.SPID, spi.SqlHandle, spi.proc_name
2984+
)
2985+
UPDATE b
2986+
SET b.implicit_conversion_info = pk.implicit_conversion_info,
2987+
b.cached_execution_parameters = pk.cached_execution_parameters
2988+
FROM ##bou_BlitzCacheProcs AS b
2989+
JOIN precheck pk
2990+
ON pk.SqlHandle = b.SqlHandle
2991+
AND pk.SPID = b.SPID
2992+
AND b.implicit_conversions = 1
2993+
OPTION(RECOMPILE);
2994+
2995+
END; --End implicit conversion information gathering
2996+
2997+
UPDATE b
2998+
SET b.implicit_conversion_info = CASE WHEN b.implicit_conversion_info IS NULL THEN '<?NoNeedToClickMe -- N/A --?>' ELSE b.implicit_conversion_info END,
2999+
b.cached_execution_parameters = CASE WHEN b.cached_execution_parameters IS NULL THEN '<?NoNeedToClickMe -- N/A --?>' ELSE b.cached_execution_parameters END
3000+
FROM ##bou_BlitzCacheProcs AS b
3001+
WHERE b.SPID = @@SPID
3002+
OPTION(RECOMPILE);
3003+
28293004
IF @SkipAnalysis = 1
28303005
BEGIN
28313006
RAISERROR(N'Skipping analysis, going to results', 0, 1) WITH NOWAIT;
@@ -3396,6 +3571,8 @@ BEGIN
33963571
QueryText AS [Query Text],
33973572
QueryType AS [Query Type],
33983573
Warnings AS [Warnings],
3574+
implicit_conversion_info AS [Implicit Conversion Info],
3575+
cached_execution_parameters AS [Cached Execution Parameters],
33993576
ExecutionCount AS [# Executions],
34003577
ExecutionsPerMinute AS [Executions / Minute],
34013578
PercentExecutions AS [Execution Weight],

0 commit comments

Comments
 (0)