@@ -210,6 +210,8 @@ CREATE TABLE ##bou_BlitzCacheProcs (
210
210
estimated_rows FLOAT ,
211
211
is_bad_estimate BIT ,
212
212
is_paul_white_electric BIT ,
213
+ implicit_conversion_info XML ,
214
+ cached_execution_parameters XML ,
213
215
SetOptions VARCHAR (MAX ),
214
216
Warnings VARCHAR (MAX )
215
217
);
@@ -891,6 +893,8 @@ BEGIN
891
893
estimated_rows FLOAT ,
892
894
is_bad_estimate BIT ,
893
895
is_paul_white_electric BIT ,
896
+ implicit_conversion_info XML ,
897
+ cached_execution_parameters XML ,
894
898
SetOptions VARCHAR (MAX ),
895
899
Warnings VARCHAR (MAX )
896
900
);
@@ -1017,6 +1021,9 @@ IF OBJECT_ID ('tempdb..#checkversion') IS NOT NULL
1017
1021
IF OBJECT_ID (' tempdb..#configuration' ) IS NOT NULL
1018
1022
DROP TABLE #configuration ;
1019
1023
1024
+ IF OBJECT_ID (' tempdb..#stored_proc_info' ) IS NOT NULL
1025
+ DROP TABLE #stored_proc_info;
1026
+
1020
1027
CREATE TABLE #only_query_hashes (
1021
1028
query_hash BINARY (8 )
1022
1029
);
@@ -1056,6 +1063,20 @@ CREATE TABLE #configuration (
1056
1063
value DECIMAL (38 ,0 )
1057
1064
);
1058
1065
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
+
1059
1080
RAISERROR (N ' Checking plan cache age' , 0 , 1 ) WITH NOWAIT ;
1060
1081
WITH x AS (
1061
1082
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
1102
1123
OPTION (RECOMPILE ) ;
1103
1124
1104
1125
1105
-
1106
1126
SET @OnlySqlHandles = LTRIM (RTRIM (@OnlySqlHandles)) ;
1107
1127
SET @OnlyQueryHashes = LTRIM (RTRIM (@OnlyQueryHashes)) ;
1108
1128
SET @IgnoreQueryHashes = LTRIM (RTRIM (@IgnoreQueryHashes)) ;
@@ -2826,6 +2846,161 @@ ON ipwe.SqlHandle = b.SqlHandle
2826
2846
WHERE b .SPID = @@SPID
2827
2847
OPTION (RECOMPILE );
2828
2848
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
+
2829
3004
IF @SkipAnalysis = 1
2830
3005
BEGIN
2831
3006
RAISERROR (N ' Skipping analysis, going to results' , 0 , 1 ) WITH NOWAIT ;
@@ -3396,6 +3571,8 @@ BEGIN
3396
3571
QueryText AS [Query Text],
3397
3572
QueryType AS [Query Type],
3398
3573
Warnings AS [Warnings],
3574
+ implicit_conversion_info AS [Implicit Conversion Info],
3575
+ cached_execution_parameters AS [Cached Execution Parameters],
3399
3576
ExecutionCount AS [# Executions],
3400
3577
ExecutionsPerMinute AS [Executions / Minute],
3401
3578
PercentExecutions AS [Execution Weight],
0 commit comments