diff --git a/Documentation/sp_Blitz Checks by Priority.md b/Documentation/sp_Blitz Checks by Priority.md index af0399438..74e132dca 100644 --- a/Documentation/sp_Blitz Checks by Priority.md +++ b/Documentation/sp_Blitz Checks by Priority.md @@ -211,6 +211,7 @@ If you want to change anything about a check - the priority, finding, URL, or ID | 200 | Non-Default Server Config | Web Assistant Procedures | http://BrentOzar.com/go/conf | 1064 | | 200 | Non-Default Server Config | xp_cmdshell | http://BrentOzar.com/go/conf | 1065 | | 200 | Performance | Buffer Pool Extensions Enabled | http://BrentOzar.com/go/bpe | 174 | +| 200 | Performance | Default Parallelism Settings | http://BrentOzar.com/go/cxpacket | 188 | | 200 | Performance | In-Memory OLTP (Hekaton) In Use | http://BrentOzar.com/go/hekaton | 146 | | 200 | Performance | Old Compatibility Level | http://BrentOzar.com/go/compatlevel | 62 | | 200 | Performance | Snapshot Backups Occurring | http://BrentOzar.com/go/snaps | 178 | diff --git a/sp_Blitz.sql b/sp_Blitz.sql index 8a054f960..a0e068858 100755 --- a/sp_Blitz.sql +++ b/sp_Blitz.sql @@ -29,7 +29,7 @@ ALTER PROCEDURE [dbo].[sp_Blitz] AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SET @VersionDate = '20161022'; + SET @VersionDate = '20161115'; SET @OutputType = UPPER(@OutputType); IF @Help = 1 PRINT ' @@ -136,7 +136,9 @@ AS ,@MsSinceWaitsCleared DECIMAL(38,0) ,@CpuMsSinceWaitsCleared DECIMAL(38,0) ,@ResultText NVARCHAR(MAX) - ,@crlf NVARCHAR(2); + ,@crlf NVARCHAR(2) + ,@Processors int + ,@NUMANodes int; SET @crlf = NCHAR(13) + NCHAR(10); @@ -1499,6 +1501,40 @@ AS WHERE cdUsed.name IS NULL; END + IF NOT EXISTS ( SELECT 1 + FROM #SkipChecks + WHERE DatabaseName IS NULL AND CheckID = 188 ) + BEGIN + + /* Let's set variables so that our query is still SARGable */ + SET @Processors = (SELECT cpu_count FROM sys.dm_os_sys_info) + SET @NUMANodes = (SELECT COUNT(1) + FROM sys.dm_os_performance_counters pc + WHERE pc.object_name LIKE '%Buffer Node%' + AND counter_name = 'Page life expectancy') + /* If Cost Threshold for Parallelism is default then flag as a potential issue */ + /* If MAXDOP is default and processors > 8 or NUMA nodes > 1 then flag as potential issue */ + INSERT INTO #BlitzResults + ( CheckID , + Priority , + FindingsGroup , + Finding , + URL , + Details + ) + SELECT 188 AS CheckID , + 200 AS Priority , + 'Performance' AS FindingsGroup , + cr.name AS Finding , + 'http://BrentOzar.com/go/cxpacket' AS URL , + ( 'Set to ' + CAST(cr.value_in_use AS NVARCHAR(50)) + ', its default value. Changing this sp_configure setting may reduce CXPACKET waits.') + FROM sys.configurations cr + INNER JOIN #ConfigurationDefaults cd ON cd.name = cr.name + AND cr.value_in_use = cd.DefaultValue + WHERE cr.name = 'cost threshold for parallelism' + OR (cr.name = 'max degree of parallelism' AND (@NUMANodes > 1 OR @Processors > 8)); + END + IF NOT EXISTS ( SELECT 1 FROM #SkipChecks diff --git a/sp_BlitzCache.sql b/sp_BlitzCache.sql index 49aca9965..ea38ba9d1 100644 --- a/sp_BlitzCache.sql +++ b/sp_BlitzCache.sql @@ -145,6 +145,13 @@ CREATE TABLE ##bou_BlitzCacheProcs ( function_count INT, clr_function_count INT, is_table_variable BIT, + no_stats_warning BIT, + relop_warnings BIT, + is_table_scan BIT, + backwards_scan BIT, + forced_index BIT, + forced_seek BIT, + forced_scan BIT, SetOptions VARCHAR(MAX), Warnings VARCHAR(MAX) ); @@ -732,12 +739,20 @@ BEGIN function_count INT, clr_function_count INT, is_table_variable BIT, + no_stats_warning BIT, + relop_warnings BIT, + is_table_scan BIT, + backwards_scan BIT, + forced_index BIT, + forced_seek BIT, + forced_scan BIT, SetOptions VARCHAR(MAX), Warnings VARCHAR(MAX) ); END DECLARE @DurationFilter_i INT, + @MinMemoryPerQuery INT, @msg NVARCHAR(4000) ; RAISERROR (N'Setting up temporary tables for sp_BlitzCache',0,1) WITH NOWAIT; @@ -756,6 +771,7 @@ BEGIN RETURN; END +SELECT @MinMemoryPerQuery = CONVERT(INT, c.value) FROM sys.configurations AS c WHERE c.name = 'min memory per query (KB)'; SET @SortOrder = LOWER(@SortOrder); SET @SortOrder = REPLACE(REPLACE(@SortOrder, 'average', 'avg'), '.', ''); @@ -1784,7 +1800,9 @@ UPDATE p SET busy_loops = CASE WHEN (x.estimated_executions / 100.0) > x.estimated_rows THEN 1 END , tvf_join = CASE WHEN x.tvf_join = 1 THEN 1 END , warning_no_join_predicate = CASE WHEN x.no_join_warning = 1 THEN 1 END, - p.is_table_variable = CASE WHEN x.is_table_variable = 1 THEN 1 END + is_table_variable = CASE WHEN x.is_table_variable = 1 THEN 1 END, + no_stats_warning = CASE WHEN x.no_stats_warning = 1 THEN 1 END, + relop_warnings = CASE WHEN x.relop_warnings = 1 THEN 1 END FROM ##bou_BlitzCacheProcs p JOIN ( SELECT qs.SqlHandle, @@ -1792,7 +1810,9 @@ FROM ##bou_BlitzCacheProcs p relop.value('sum(/p:RelOp/@EstimateRewinds)', 'float') + relop.value('sum(/p:RelOp/@EstimateRebinds)', 'float') + 1.0 AS estimated_executions , relop.exist('/p:RelOp[contains(@LogicalOp, "Join")]/*/p:RelOp[(@LogicalOp[.="Table-valued function"])]') AS tvf_join, relop.exist('/p:RelOp/p:Warnings[(@NoJoinPredicate[.="1"])]') AS no_join_warning, - relop.exist('/p:RelOp//*[local-name() = "Object"]/@Table[contains(., "@")]') AS is_table_variable + relop.exist('/p:RelOp//*[local-name() = "Object"]/@Table[contains(., "@")]') AS is_table_variable, + relop.exist('/p:RelOp/p:Warnings/p:ColumnsWithNoStatistics') AS no_stats_warning , + relop.exist('/p:RelOp/p:Warnings') AS relop_warnings FROM #relop qs ) AS x ON p.SqlHandle = x.SqlHandle OPTION (RECOMPILE); @@ -1819,7 +1839,7 @@ SET key_lookup_cost = x.key_lookup_cost FROM ( SELECT qs.SqlHandle, - relop.value('/p:RelOp[1]/@EstimatedTotalSubtreeCost', 'float') AS key_lookup_cost + relop.value('sum(/p:RelOp/@EstimatedTotalSubtreeCost)', 'float') AS key_lookup_cost FROM #relop qs WHERE [relop].exist('/p:RelOp/p:IndexScan[(@Lookup[.="1"])]') = 1 ) AS x @@ -1833,7 +1853,7 @@ SET remote_query_cost = x.remote_query_cost FROM ( SELECT qs.SqlHandle, - relop.value('/p:RelOp[1]/@EstimatedTotalSubtreeCost', 'float') AS remote_query_cost + relop.value('sum(/p:RelOp/@EstimatedTotalSubtreeCost)', 'float') AS remote_query_cost FROM #relop qs WHERE [relop].exist('/p:RelOp[(@PhysicalOp[.="Remote Query"])]') = 1 ) AS x @@ -1851,6 +1871,38 @@ ON b.QueryHash = qs.QueryHash CROSS APPLY qs.statement.nodes('/p:StmtCursor') AS n1(fn) OPTION (RECOMPILE) ; +;WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) +UPDATE b +SET +b.is_table_scan = x.is_table_scan, +b.backwards_scan = x.backwards_scan, +b.forced_index = x.forced_index, +b.forced_seek = x.forced_seek, +b.forced_scan = x.forced_scan +FROM ##bou_BlitzCacheProcs b +JOIN ( +SELECT + qs.SqlHandle, + 0 AS is_table_scan, + q.n.exist('@ScanDirection[.="BACKWARD"]') AS backwards_scan, + q.n.value('@ForcedIndex', 'bit') AS forced_index, + q.n.value('@ForceSeek', 'bit') AS forced_seek, + q.n.value('@ForceScan', 'bit') AS forced_scan +FROM #relop qs +CROSS APPLY qs.relop.nodes('//p:IndexScan') AS q(n) +UNION ALL +SELECT + qs.SqlHandle, + 1 AS is_table_scan, + q.n.exist('@ScanDirection[.="BACKWARD"]') AS backwards_scan, + q.n.value('@ForcedIndex', 'bit') AS forced_index, + q.n.value('@ForceSeek', 'bit') AS forced_seek, + q.n.value('@ForceScan', 'bit') AS forced_scan +FROM #relop qs +CROSS APPLY qs.relop.nodes('//p:TableScan') AS q(n) +) AS x ON b.SqlHandle = x.SqlHandle +OPTION (RECOMPILE) ; + IF @v >= 12 BEGIN @@ -2051,7 +2103,7 @@ SET frequent_execution = CASE WHEN ExecutionsPerMinute > @execution_threshold is_key_lookup_expensive = CASE WHEN QueryPlanCost > (@ctp / 2) AND key_lookup_cost >= QueryPlanCost * .5 THEN 1 END, is_remote_query_expensive = CASE WHEN remote_query_cost >= QueryPlanCost * .05 THEN 1 END, is_forced_serial = CASE WHEN is_forced_serial = 1 AND QueryPlanCost > (@ctp / 2) THEN 1 END, - is_unused_grant = CASE WHEN PercentMemoryGrantUsed <= @memory_grant_warning_percent AND MinGrantKB > 0 THEN 1 END + is_unused_grant = CASE WHEN PercentMemoryGrantUsed <= @memory_grant_warning_percent AND MinGrantKB > @MinMemoryPerQuery THEN 1 END OPTION (RECOMPILE) ; @@ -2126,7 +2178,14 @@ SET Warnings = SUBSTRING( CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), function_count) + ' function(s)' ELSE '' END + CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), clr_function_count) + ' CLR function(s)' ELSE '' END + CASE WHEN PlanCreationTimeHours <= 4 THEN ', Plan created last 4hrs' ELSE '' END + - CASE WHEN is_table_variable = 1 THEN ', Table Variables' ELSE '' END + CASE WHEN is_table_variable = 1 THEN ', Table Variables' ELSE '' END + + CASE WHEN no_stats_warning = 1 THEN ', Columns With No Statistics' ELSE '' END + + CASE WHEN relop_warnings = 1 THEN ', Operator Warnings' ELSE '' END + + CASE WHEN is_table_scan = 1 THEN ', Table Scans' ELSE '' END + + CASE WHEN backwards_scan = 1 THEN ', Backwards Scans' ELSE '' END + + CASE WHEN forced_index = 1 THEN ', Forced Indexes' ELSE '' END + + CASE WHEN forced_seek = 1 THEN ', Forced Seeks' ELSE '' END + + CASE WHEN forced_scan = 1 THEN ', Forced Scans' ELSE '' END , 2, 200000) OPTION (RECOMPILE) ; @@ -2135,12 +2194,6 @@ SET Warnings = SUBSTRING( - - - - - - Results: IF @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL @@ -2440,7 +2493,13 @@ BEGIN CASE WHEN function_count > 0 IS NOT NULL THEN '', 31'' ELSE '''' END + CASE WHEN clr_function_count > 0 THEN '', 32'' ELSE '''' END + CASE WHEN PlanCreationTimeHours <= 4 THEN '', 33'' ELSE '''' END + - CASE WHEN is_table_variable = 1 then '', 34'' ELSE '''' END + CASE WHEN is_table_variable = 1 THEN '', 34'' ELSE '''' END + + CASE WHEN no_stats_warning = 1 THEN '', 35'' ELSE '''' END + + CASE WHEN relop_warnings = 1 THEN '', 36'' ELSE '''' END + + CASE WHEN is_table_scan = 1 THEN '', 37'' ELSE '''' END + + CASE WHEN backwards_scan = 1 THEN '', 38'' ELSE '''' END + + CASE WHEN forced_index = 1 THEN '', 39'' ELSE '''' END + + CASE WHEN forced_seek = 1 OR forced_scan = 1 THEN '', 40'' ELSE '''' END , 2, 200000) AS opserver_warning , ' + @nl ; END @@ -2902,7 +2961,7 @@ BEGIN 100, 'Unused memory grants', 'Queries are asking for more memory than they''re using', - 'No URL yet.', + 'https://www.brentozar.com/blitzcache/unused-memory-grants/', 'Queries have large unused memory grants. This can cause concurrency issues, if queries are waiting a long time to get memory to run.') ; IF EXISTS (SELECT 1/0 @@ -2915,7 +2974,7 @@ BEGIN 100, 'Compute Scalar That References A Function', 'This could be trouble if you''re using Scalar Functions or MSTVFs', - 'No URL yet.', + 'https://www.brentozar.com/blitzcache/compute-scalar-functions/', 'Both of these will force queries to run serially, run at least once per row, and may result in poor cardinality estimates') ; IF EXISTS (SELECT 1/0 @@ -2928,7 +2987,7 @@ BEGIN 100, 'Compute Scalar That References A CLR Function', 'This could be trouble if your CLR functions perform data access', - 'No URL yet.', + 'https://www.brentozar.com/blitzcache/compute-scalar-functions/', 'May force queries to run serially, run at least once per row, and may result in poor cardinlity estimates') ; @@ -2942,9 +3001,89 @@ BEGIN 100, 'Table Variables detected', 'Beware nasty side effects', - 'No URL yet.', + 'https://www.brentozar.com/blitzcache/table-variables/', 'All modifications are single threaded, and selects have really low row estimates.') ; + IF EXISTS (SELECT 1/0 + FROM ##bou_BlitzCacheProcs p + WHERE p.no_stats_warning = 1 + AND SPID = @@SPID) + INSERT INTO ##bou_BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) + VALUES (@@SPID, + 35, + 100, + 'Columns with no statistics', + 'Poor cardinality estimates may ensue', + 'https://www.brentozar.com/blitzcache/columns-no-statistics/', + 'Sometimes this happens with indexed views, other times because auto create stats is turned off.') ; + + IF EXISTS (SELECT 1/0 + FROM ##bou_BlitzCacheProcs p + WHERE p.relop_warnings = 1 + AND SPID = @@SPID) + INSERT INTO ##bou_BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) + VALUES (@@SPID, + 36, + 100, + 'Operator Warnings', + 'SQL is throwing operator level plan warnings', + 'http://brentozar.com/blitzcache/query-plan-warnings/', + 'Check the plan for more details.') ; + + IF EXISTS (SELECT 1/0 + FROM ##bou_BlitzCacheProcs p + WHERE p.is_table_scan = 1 + AND SPID = @@SPID) + INSERT INTO ##bou_BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) + VALUES (@@SPID, + 37, + 100, + 'Table Scans', + 'Your database has HEAPs', + 'https://www.brentozar.com/archive/2012/05/video-heaps/', + 'This may not be a problem. Run sp_BlitzIndex for more information.') ; + + IF EXISTS (SELECT 1/0 + FROM ##bou_BlitzCacheProcs p + WHERE p.backwards_scan = 1 + AND SPID = @@SPID) + INSERT INTO ##bou_BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) + VALUES (@@SPID, + 38, + 100, + 'Backwards Scans', + 'Indexes are being read backwards', + 'https://www.brentozar.com/blitzcache/backwards-scans/', + 'This isn''t always a problem. They can cause serial zones in plans, and may need an index to match sort order.') ; + + IF EXISTS (SELECT 1/0 + FROM ##bou_BlitzCacheProcs p + WHERE p.forced_index = 1 + AND SPID = @@SPID) + INSERT INTO ##bou_BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) + VALUES (@@SPID, + 39, + 100, + 'Index forcing', + 'Someone is using hints to force index usage', + 'https://www.brentozar.com/blitzcache/optimizer-forcing/', + 'This can cause inefficient plans, and will prevent missing index requests.') ; + + IF EXISTS (SELECT 1/0 + FROM ##bou_BlitzCacheProcs p + WHERE p.forced_seek = 1 + OR p.forced_scan = 1 + AND SPID = @@SPID) + INSERT INTO ##bou_BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) + VALUES (@@SPID, + 40, + 100, + 'Seek/Scan forcing', + 'Someone is using hints to force index seeks/scans', + 'https://www.brentozar.com/blitzcache/optimizer-forcing/', + 'This can cause inefficient plans by taking seek vs scan choice away from the optimizer.') ; + + IF EXISTS (SELECT 1/0 FROM #plan_creation p WHERE p.percent_24 > 0 @@ -2956,11 +3095,10 @@ BEGIN 254, 'Plan Cache Information', 'You have ' + CONVERT(NVARCHAR(10), p.percent_24) + '% plans created in the past 24 hours, and ' + CONVERT(NVARCHAR(10), p.percent_4) + '% created in the past 4 hours.', - 'No URL yet.', + '', 'If these percentages are high, it may be a sign of memory pressure or plan cache instability.' FROM #plan_creation p ; - IF EXISTS (SELECT 1/0 FROM #trace_flags AS tf WHERE tf.global_trace_flags IS NOT NULL diff --git a/sp_BlitzIndex.sql b/sp_BlitzIndex.sql index 7dda45e2d..790175b90 100644 --- a/sp_BlitzIndex.sql +++ b/sp_BlitzIndex.sql @@ -21,6 +21,7 @@ ALTER PROCEDURE dbo.sp_BlitzIndex @Filter TINYINT = 0, /* 0=no filter (default). 1=No low-usage warnings for objects with 0 reads. 2=Only warn for objects >= 500MB */ /*Note:@Filter doesn't do anything unless @Mode=0*/ @SkipPartitions BIT = 0, + @SkipStatistics BIT = 1, @GetAllDatabases BIT = 0, @BringThePain BIT = 0, @ThresholdMB INT = 250 /* Number of megabytes that an object must be before we include it in basic results */, @@ -35,8 +36,8 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; DECLARE @Version VARCHAR(30); -SET @Version = '4.4'; -SET @VersionDate = '20161022'; +SET @Version = '4.5'; +SET @VersionDate = '20161115'; IF @Help = 1 PRINT ' /* sp_BlitzIndex from http://FirstResponderKit.org @@ -688,9 +689,9 @@ BEGIN TRY IF (SELECT LEFT(@SQLServerProductVersion, CHARINDEX('.',@SQLServerProductVersion,0)-1 - )) <= 8 + )) <= 9 BEGIN - SET @msg=N'sp_BlitzIndex is only supported on SQL Server 2005 and higher. The version of this instance is: ' + @SQLServerProductVersion; + SET @msg=N'sp_BlitzIndex is only supported on SQL Server 2008 and higher. The version of this instance is: ' + @SQLServerProductVersion; RAISERROR(@msg,16,1); END @@ -1458,6 +1459,8 @@ BEGIN TRY + IF @SkipStatistics = 0 + BEGIN IF ((PARSENAME(@SQLServerProductVersion, 4) >= 12) OR (PARSENAME(@SQLServerProductVersion, 4) = 11 AND PARSENAME(@SQLServerProductVersion, 2) >= 3000) OR (PARSENAME(@SQLServerProductVersion, 4) = 10 AND PARSENAME(@SQLServerProductVersion, 3) = 50 AND PARSENAME(@SQLServerProductVersion, 2) >= 2500)) @@ -1551,19 +1554,19 @@ BEGIN TRY NULL AS filter_definition' END + N' FROM ' + QUOTENAME(@DatabaseName) + N'.sys.stats AS s - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.sysindexes si + INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.sysindexes si ON si.name = s.name - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.stats_columns sc + INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.stats_columns sc ON sc.object_id = s.object_id AND sc.stats_id = s.stats_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns c + INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns c ON c.object_id = sc.object_id AND c.column_id = sc.column_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects obj + INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects obj ON s.object_id = obj.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sch + INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sch ON sch.schema_id = obj.schema_id - LEFT JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.indexes AS i + LEFT HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.indexes AS i ON i.object_id = s.object_id AND i.index_id = s.stats_id WHERE obj.is_ms_shipped = 0 @@ -1582,6 +1585,8 @@ BEGIN TRY EXEC sp_executesql @dsql; END + END + IF (PARSENAME(@SQLServerProductVersion, 4) >= 10) BEGIN RAISERROR (N'Gathering Computed Column Info.',0,1) WITH NOWAIT; @@ -1594,9 +1599,10 @@ BEGIN TRY cc.uses_database_collation, cc.is_persisted, cc.is_computed, - CASE WHEN cc.definition LIKE ''%dbo%'' THEN 1 ELSE 0 END AS is_function, + CASE WHEN cc.definition LIKE ''%.%'' THEN 1 ELSE 0 END AS is_function, ''ALTER TABLE '' + QUOTENAME(s.name) + ''.'' + QUOTENAME(t.name) + - '' ADD '' + QUOTENAME(c.name) + '' AS '' + cc.definition + '';'' AS [column_definition] + '' ADD '' + QUOTENAME(c.name) + '' AS '' + cc.definition + + CASE WHEN is_persisted = 1 THEN '' PERSISTED'' ELSE '''' END + '';'' AS [column_definition] FROM ' + QUOTENAME(@DatabaseName) + N'.sys.computed_columns AS cc JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c ON cc.object_id = c.object_id @@ -3219,7 +3225,7 @@ BEGIN; 'Filter Fixation', s.database_name, '' AS URL, - 'The statistic ' + QUOTENAME(s.statistics_name) + ' is filtered on ' + QUOTENAME(s.filter_definition) + '. It could be part of a filtered index, or just a filtered statistic. This is purely informational.' , + 'The statistic ' + QUOTENAME(s.statistics_name) + ' is filtered on [' + s.filter_definition + ']. It could be part of a filtered index, or just a filtered statistic. This is purely informational.' , QUOTENAME(database_name) + '.' + QUOTENAME(s.schema_name) + '.' + QUOTENAME(s.table_name) + '.' + QUOTENAME(s.index_name) + '.' + QUOTENAME(s.statistics_name) + '.' + QUOTENAME(s.column_name) AS index_definition, 'N/A' AS secret_columns, 'N/A' AS index_usage_summary, @@ -3579,4 +3585,4 @@ BEGIN CATCH RETURN; END CATCH; -GO \ No newline at end of file +GO