There are several system dynamic management views (DMV) available in SQL Server, Azure SQL Server and now in SQL databases that allow to gather more information about indexes' fragmentation and usage. Let's look at the most important information available based on the indexes create in the previous posts. As the data were probably purged from the views, it's needed to run first the select queries based on the SalesLT.Product from the previous post. This step is important, otherwise the DMVs might return no records!
One starting point is to use the sys.dm_db_index_physical_stats DMV to look at the indexes' size and fragmentation information for a given table (or view). The table is used usually as starting point for analyzing indexes' fragmentation and then defragment the indexes with high fragmentation.
-- sys metadata - index & data size and fragmentation information for the data and indexes of the specified table or view SELECT --db_name() db_name --, object_name(IND.object_id) table_name IND.name index_name , IND.type_desc , IPS.page_count , IPS.record_count , IPS.index_level , Cast(IPS.avg_fragmentation_in_percent as decimal(10,2)) avg_fragmentation_perc , Cast(IPS.avg_page_space_used_in_percent as decimal(10,2)) space_used_perc --, IPS.* FROM sys.indexes IND CROSS APPLY sys.dm_db_index_physical_stats(DB_ID(), IND.object_id, IND.index_id, NULL, 'DETAILED') IPS WHERE IND.object_id = OBJECT_ID(N'SalesLT.Product');
index_name | type_desc | page_count | record_count | index_level | avg_fragmentation_perc | space_used_perc |
PK_Product_ProductID | CLUSTERED | 101 | 295 | 0 | 0.99 | 87.90 |
PK_Product_ProductID | CLUSTERED | 1 | 101 | 1 | 0.00 | 16.20 |
AK_Product_rowguid | NONCLUSTERED | 2 | 295 | 0 | 50.00 | 74.69 |
AK_Product_rowguid | NONCLUSTERED | 1 | 2 | 1 | 0.00 | 0.59 |
AK_Product_ProductNumber | NONCLUSTERED | 2 | 295 | 0 | 50.00 | 85.79 |
AK_Product_ProductNumber | NONCLUSTERED | 1 | 2 | 1 | 0.00 | 0.49 |
AK_Product_Name | NONCLUSTERED | 3 | 295 | 0 | 33.33 | 87.32 |
AK_Product_Name | NONCLUSTERED | 1 | 3 | 1 | 0.00 | 1.67 |
IX_SalesLT_Product_Color | NONCLUSTERED | 1 | 295 | 0 | 0.00 | 79.24 |
IX_SalesLT_Product_Color_Size | NONCLUSTERED | 1 | 295 | 0 | 0.00 | 94.12 |
IX_SalesLT_Product_ListPrice_IC | NONCLUSTERED | 4 | 295 | 0 | 0.00 | 86.60 |
IX_SalesLT_Product_ListPrice_IC | NONCLUSTERED | 1 | 4 | 1 | 0.00 | 1.01 |
In a second step one can look at the sys.dm_db_index_usage_stats DMV which provides the counts of the different types of index operations and the time each type of operation was last performed:
-- sys metadata - counts of different types of index operations and the time each type of operation was last performed. SELECT -- db_name() db_name --, object_name(IND.object_id) table_name IND.name , IND.type_desc , IUS.user_seeks , IUS.user_scans , IUS.user_lookups , IUS.user_updates , IUS.last_user_seek , IUS.last_user_scan , IUS.last_user_lookup , IUS.last_user_update FROM sys.dm_db_index_usage_stats IUS JOIN sys.indexes IND ON IUS.index_id = IND.index_id WHERE IND.object_id = OBJECT_ID(N'SalesLT.Product');
name | type_desc | user_seeks | user_scans | user_lookups | user_updates | last_user_seek | last_user_scan | last_user_lookup |
PK_Product_ProductID | CLUSTERED | 0 | 10 | 15 | 0 | 2025-01-06T14:23:54 | 2025-01-06T14:23:54 | |
IX_SalesLT_Product_Color_Size | NONCLUSTERED | 11 | 0 | 0 | 0 | 2025-01-06T14:23:54 | ||
IX_SalesLT_Product_ListPrice_IC | NONCLUSTERED | 8 | 0 | 0 | 0 | 2025-01-06T13:38:03 |
Finally, it might be useful to look also at the sys.dm_db_index_operational_stats DMV which returns the current lower-level I/O, locking, latching, and access method activity for each partition of a table or index in the database (see the documentation for the full list of attrbutes):
-- sys metadata - index operations stats SELECT -- db_name() db_name --, object_name(IND.object_id) table_name IND.name index_name , IND.type_desc , IOS.range_scan_count , IOS.singleton_lookup_count , IOS.leaf_insert_count , IOS.leaf_delete_count , IOS.leaf_update_count , IOS.nonleaf_insert_count , IOS.nonleaf_delete_count , IOS.nonleaf_update_count FROM sys.indexes IND CROSS APPLY sys.dm_db_index_operational_stats(DB_ID(), IND.object_id, IND.index_id, NULL) IOS WHERE IND.object_id = OBJECT_ID(N'SalesLT.Product') AND IOS.range_scan_count<>0 ORDER BY IND.name;
index_name | type_desc | range_scan_count | singleton_lookup_count | leaf_insert_count | leaf_delete_count | leaf_update_count | nonleaf_insert_count | nonleaf_delete_count | nonleaf_update_count |
IX_SalesLT_Product_Color_Size | NONCLUSTERED | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
IX_SalesLT_Product_ListPrice_IC | NONCLUSTERED | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
PK_Product_ProductID | CLUSTERED | 10 | 64 | 0 | 0 | 0 | 0 | 0 | 0 |
For more information on these DMVs check the documentation.
Happy coding!
Previous Post <<||>> Next Post
References:
[1] Microsoft Learn (2024) SQL
Server: sys.dm_db_index_physical_stats [link]
[2] Microsoft Learn (2024) SQL
Server: sys.dm_db_index_usage_stats [link]
[3] Microsoft Learn (2024) SQL Server:
sys.dm_db_index_operational_stats [link]
No comments:
Post a Comment