@@ -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
10171021IF 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+
10201027CREATE 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+
10591080RAISERROR (N ' Checking plan cache age' , 0 , 1 ) WITH NOWAIT ;
10601081WITH x AS (
10611082SELECT 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
11021123OPTION (RECOMPILE ) ;
11031124
11041125
1105-
11061126SET @OnlySqlHandles = LTRIM (RTRIM (@OnlySqlHandles)) ;
11071127SET @OnlyQueryHashes = LTRIM (RTRIM (@OnlyQueryHashes)) ;
11081128SET @IgnoreQueryHashes = LTRIM (RTRIM (@IgnoreQueryHashes)) ;
@@ -2826,6 +2846,161 @@ ON ipwe.SqlHandle = b.SqlHandle
28262846WHERE b .SPID = @@SPID
28272847OPTION (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+
28293004IF @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