@@ -503,7 +503,7 @@ IF OBJECT_ID('tempdb..#dm_db_index_operational_stats') IS NOT NULL
503503 THEN ( user_seeks + user_scans + user_lookups ) / (1 .0 * user_updates)
504504 ELSE 0 END AS MONEY ) ,
505505 [index_usage_summary] AS
506- CASE WHEN is_spatial = 1 THEN N ' Not Tracked'
506+ CASE WHEN is_spatial = 1 OR is_json = 1 THEN N ' Not Tracked'
507507 WHEN is_disabled = 1 THEN N ' Disabled'
508508 ELSE N ' Reads: ' +
509509 REPLACE (CONVERT (NVARCHAR (30 ),CAST ((user_seeks + user_scans + user_lookups) AS MONEY ), 1 ), N ' .00' , N ' ' )
@@ -1795,7 +1795,7 @@ BEGIN TRY
17951795 CASE WHEN ( @IncludeInactiveIndexes = 0
17961796 AND @Mode IN (0 , 4 )
17971797 AND @TableName IS NULL )
1798- THEN N ' AND ( us.user_seeks + us.user_scans + us.user_lookups + us.user_updates ) > 0'
1798+ THEN N ' AND ( us.user_seeks + us.user_scans + us.user_lookups + us.user_updates > 0 OR si.type = 9 ) '
17991799 ELSE N ' '
18001800 END
18011801 + N' OPTION ( RECOMPILE );
@@ -2201,6 +2201,54 @@ BEGIN TRY
22012201
22022202 END ; -- End Check For @SkipPartitions = 0
22032203
2204+ /* Populate JSON index sizes from internal tables - JSON indexes store their data
2205+ in sys.internal_tables, not in sys.dm_db_partition_stats for the parent table */
2206+ IF EXISTS (SELECT * FROM sys .all_objects WHERE name = ' json_indexes' )
2207+ BEGIN
2208+ RAISERROR (N ' Inserting JSON index size data from internal tables' ,0 ,1 ) WITH NOWAIT ;
2209+ SET @dsql = N' SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
2210+ SELECT ' + CAST (@DatabaseID AS NVARCHAR (10 )) + N' AS database_id,
2211+ it.parent_id AS object_id,
2212+ s.name AS schema_name,
2213+ it.parent_minor_id AS index_id,
2214+ ps.partition_number,
2215+ ps.row_count,
2216+ ps.reserved_page_count * 8. / 1024. AS reserved_MB,
2217+ ps.lob_reserved_page_count * 8. / 1024. AS reserved_LOB_MB,
2218+ ps.row_overflow_reserved_page_count * 8. / 1024. AS reserved_row_overflow_MB,
2219+ NULL AS lock_escalation_desc,
2220+ NULL AS data_compression_desc,
2221+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2222+ 0 AS reserved_dictionary_MB
2223+ FROM ' + QUOTENAME (@DatabaseName) + N' .sys.internal_tables it
2224+ JOIN ' + QUOTENAME (@DatabaseName) + N' .sys.dm_db_partition_stats ps ON it.object_id = ps.object_id AND ps.index_id = 1
2225+ JOIN ' + QUOTENAME (@DatabaseName) + N' .sys.objects so ON it.parent_id = so.object_id
2226+ JOIN ' + QUOTENAME (@DatabaseName) + N' .sys.schemas s ON so.schema_id = s.schema_id
2227+ WHERE it.internal_type_desc = '' JSON_INDEX_TABLE''
2228+ ' + CASE WHEN @ObjectID IS NOT NULL THEN N ' AND it.parent_id = ' + CAST (@ObjectID AS NVARCHAR (30 )) + N ' ' ELSE N ' ' END + N'
2229+ OPTION (RECOMPILE);' ;
2230+
2231+ IF @Debug = 1
2232+ BEGIN
2233+ PRINT SUBSTRING (@dsql, 0 , 4000 );
2234+ PRINT SUBSTRING (@dsql, 4000 , 8000 );
2235+ END ;
2236+
2237+ INSERT #IndexPartitionSanity ( [database_id], [object_id], [schema_name], index_id, partition_number,
2238+ row_count, reserved_MB, reserved_LOB_MB, reserved_row_overflow_MB,
2239+ lock_escalation_desc, data_compression_desc,
2240+ leaf_insert_count, leaf_delete_count, leaf_update_count,
2241+ range_scan_count, singleton_lookup_count, forwarded_fetch_count,
2242+ lob_fetch_in_pages, lob_fetch_in_bytes,
2243+ row_overflow_fetch_in_pages, row_overflow_fetch_in_bytes,
2244+ row_lock_count, row_lock_wait_count, row_lock_wait_in_ms,
2245+ page_lock_count, page_lock_wait_count, page_lock_wait_in_ms,
2246+ index_lock_promotion_attempt_count, index_lock_promotion_count,
2247+ page_latch_wait_count, page_latch_wait_in_ms,
2248+ page_io_latch_wait_count, page_io_latch_wait_in_ms,
2249+ reserved_dictionary_MB)
2250+ EXEC sp_executesql @dsql;
2251+ END ;
22042252
22052253 IF @Mode NOT IN (1 , 2 )
22062254 BEGIN
@@ -3200,6 +3248,42 @@ FROM #IndexSanity si
32003248 AND c .index_id = si .index_id
32013249 ) AS D4 ( count_included_columns, count_key_columns );
32023250
3251+ /* JSON indexes have key_ordinal=0 in sys.index_columns, so the above updates skip them.
3252+ Populate column names for JSON indexes from #IndexColumns where key_ordinal = 0. */
3253+ RAISERROR (N ' Updating column names for JSON indexes' ,0 ,1 ) WITH NOWAIT ;
3254+ UPDATE si
3255+ SET key_column_names = c .column_name
3256+ + N ' {' + c .system_type_name
3257+ + CASE c .max_length WHEN - 1 THEN N ' (max)' ELSE
3258+ CASE
3259+ WHEN c .system_type_name IN (N ' char' ,N ' varchar' ,N ' binary' ,N ' varbinary' ) THEN N ' (' + CAST (c .max_length AS NVARCHAR (20 )) + N ' )'
3260+ WHEN c .system_type_name IN (N ' nchar' ,N ' nvarchar' ) THEN N ' (' + CAST (c .max_length / 2 AS NVARCHAR (20 )) + N ' )'
3261+ ELSE N ' ' + CAST (c .max_length AS NVARCHAR (50 ))
3262+ END
3263+ END
3264+ + N ' }' ,
3265+ key_column_names_with_sort_order = c .column_name
3266+ + N ' {' + c .system_type_name
3267+ + CASE c .max_length WHEN - 1 THEN N ' (max)' ELSE
3268+ CASE
3269+ WHEN c .system_type_name IN (N ' char' ,N ' varchar' ,N ' binary' ,N ' varbinary' ) THEN N ' (' + CAST (c .max_length AS NVARCHAR (20 )) + N ' )'
3270+ WHEN c .system_type_name IN (N ' nchar' ,N ' nvarchar' ) THEN N ' (' + CAST (c .max_length / 2 AS NVARCHAR (20 )) + N ' )'
3271+ ELSE N ' ' + CAST (c .max_length AS NVARCHAR (50 ))
3272+ END
3273+ END
3274+ + N ' }' ,
3275+ key_column_names_with_sort_order_no_types = QUOTENAME (c .column_name ),
3276+ count_key_columns = 1
3277+ FROM #IndexSanity si
3278+ JOIN #IndexColumns c ON si .database_id = c .database_id
3279+ AND si .schema_name = c .schema_name
3280+ AND si .object_id = c .object_id
3281+ AND si .index_id = c .index_id
3282+ AND c .key_ordinal = 0
3283+ AND c .is_included_column = 0
3284+ WHERE si .is_json = 1
3285+ AND si .key_column_names IS NULL ;
3286+
32033287RAISERROR (N ' Updating index_sanity_id on #IndexPartitionSanity' ,0 ,1 ) WITH NOWAIT ;
32043288UPDATE #IndexPartitionSanity
32053289SET index_sanity_id = i .index_sanity_id
@@ -3322,7 +3406,11 @@ SELECT
33223406 CASE index_id WHEN 0 THEN N ' ALTER TABLE ' + QUOTENAME ([database_name]) + N ' .' + QUOTENAME ([schema_name]) + N ' .' + QUOTENAME ([object_name]) + ' REBUILD;'
33233407 ELSE
33243408 CASE WHEN is_XML = 1 OR is_spatial = 1 OR is_in_memory_oltp = 1 THEN N ' ' /* Not even trying for these just yet...*/
3325- ELSE
3409+ WHEN is_json = 1 THEN
3410+ N ' CREATE JSON INDEX ' + QUOTENAME (index_name) + N ' ON ' +
3411+ QUOTENAME ([database_name]) + N ' .' + QUOTENAME ([schema_name]) + N ' .' + QUOTENAME ([object_name]) +
3412+ N ' (' + ISNULL (key_column_names_with_sort_order_no_types, N ' ' ) + N ' );'
3413+ ELSE
33263414 CASE WHEN is_primary_key= 1 THEN
33273415 N ' ALTER TABLE ' + QUOTENAME ([database_name]) + N ' .' + QUOTENAME ([schema_name]) +
33283416 N ' .' + QUOTENAME ([object_name]) +
@@ -5798,7 +5886,27 @@ BEGIN
57985886 ISNULL (sz .index_size_summary ,' ' ) AS index_size_summary
57995887 FROM #IndexSanity AS i
58005888 JOIN #IndexSanitySize sz ON i .index_sanity_id = sz .index_sanity_id
5801- WHERE i .is_spatial = 1
5889+ Where i .is_spatial = 1
5890+ OPTION ( RECOMPILE );
5891+
5892+ RAISERROR (N ' check_id 129: JSON indexes' , 0 ,1 ) WITH NOWAIT ;
5893+ INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL , details, index_definition,
5894+ secret_columns, index_usage_summary, index_size_summary )
5895+ SELECT 129 AS check_id,
5896+ i .index_sanity_id ,
5897+ 150 AS Priority,
5898+ N ' Feature-Dependent Indexes' AS findings_group,
5899+ N ' JSON Index' AS finding,
5900+ [database_name] AS [Database Name],
5901+ N ' https://www.brentozar.com/go/AbnormalPsychology' AS URL ,
5902+ i .db_schema_object_indexid AS details,
5903+ i .index_definition ,
5904+ i .secret_columns ,
5905+ i .index_usage_summary ,
5906+ ISNULL (sz .index_size_summary ,' ' ) AS index_size_summary
5907+ FROM #IndexSanity AS i
5908+ JOIN #IndexSanitySize sz ON i .index_sanity_id = sz .index_sanity_id
5909+ WHERE i .is_json = 1
58025910 OPTION ( RECOMPILE );
58035911
58045912 RAISERROR (N ' check_id 63: Compressed indexes' , 0 ,1 ) WITH NOWAIT ;
0 commit comments