Notes to myself – Indexes

SQL PM at Microsoft Ignite

-- Script to generate SQL commands for disabling unused or less used indexes
USE [pwLegalOffice]; -- Change this to your database name
GO

DECLARE @DisableCommands NVARCHAR(MAX);
SET @DisableCommands = '';

WITH IndexUsageStats AS (
    SELECT
        OBJECT_NAME(i.OBJECT_ID) AS TableName,
        i.name AS IndexName,
        SUM(user_seeks + user_scans + user_lookups) AS TotalReads,
        SUM(user_updates) AS TotalWrites,
        i.index_id,
        i.OBJECT_ID AS TableObjectId
    FROM
        sys.indexes AS i
    INNER JOIN
        sys.dm_db_index_usage_stats AS s ON i.OBJECT_ID = s.OBJECT_ID AND i.index_id = s.index_id
    WHERE
        OBJECTPROPERTY(i.OBJECT_ID, 'IsUserTable') = 1
        AND s.database_id = DB_ID() -- Ensure we're only looking at the current database
    GROUP BY
        i.OBJECT_ID, i.name, i.index_id
),
IndexPhysicalStats AS (
    SELECT
        OBJECT_NAME(OBJECT_ID) AS TableName,
        index_id,
        SUM(row_count) AS [RowCount],
        SUM(used_page_count) * 8 AS IndexSizeKB -- Convert pages to KB
    FROM
        sys.dm_db_partition_stats
    GROUP BY
        OBJECT_ID, index_id
),
UnusedIndexes AS (
    SELECT
        u.TableName,
        u.IndexName
    FROM
        IndexUsageStats AS u
    LEFT JOIN
        IndexPhysicalStats AS p ON u.TableName = p.TableName AND u.index_id = p.index_id
    WHERE
        u.TotalReads = 0 -- Indexes with zero reads
        OR u.TotalReads < u.TotalWrites -- Or, indexes with more writes than reads
)
SELECT
    @DisableCommands = @DisableCommands + 'ALTER INDEX [' + IndexName + '] ON [' + TableName + '] DISABLE;' + CHAR(13)
FROM
    UnusedIndexes;

-- Print out the commands to disable indexes
PRINT @DisableCommands;

-- Execute the command
--Exec @DisableCommands;


-- Index fragmentation information
SELECT  Tab.name  Table_Name 
			 ,IX.name  Index_Name
			 ,IX.type_desc Index_Type
			 ,Col.name  Index_Column_Name
			 ,IXC.is_included_column Is_Included_Column
			 ,IX.fill_factor 
			 ,IX.is_disabled
			 ,IX.is_primary_key
			 ,IX.is_unique
			 		  
           FROM  sys.indexes IX 
           INNER JOIN sys.index_columns IXC  ON  IX.object_id   =   IXC.object_id AND  IX.index_id  =  IXC.index_id  
           INNER JOIN sys.columns Col   ON  IX.object_id   =   Col.object_id  AND IXC.column_id  =   Col.column_id     
           INNER JOIN sys.tables Tab      ON  IX.object_id = Tab.object_id
-- Index structure information and statistics 

-- List all index in a sigle table
sp_helpindex '[dbo].[Contact]'

-- Update statistics in a single table using fullscan 
-- ( for more critical and most updated tables )
UPDATE STATISTICS tableName indexName WITH FULLSCAN;

-- Update statistics in a single table
UPDATE STATISTICS [dbo].[Contact];

-- Update statistics for all tables in a database
EXEC sp_updatestats;

-- Set automatically update statistics as needed
ALTER DATABASE [pwLegalOffice] SET AUTO_UPDATE_STATISTICS ON;

-- Set automatically update statistics as needed 
-- (This allows queries to use existing statistics while new statistics are being generated) 
ALTER DATABASE [pwLegalOffice] SET AUTO_UPDATE_STATISTICS_ASYNC ON;

-- Index usage information
SELECT OBJECT_NAME(IX.OBJECT_ID) Table_Name
	   ,IX.name AS Index_Name
	   ,IX.type_desc Index_Type
	   ,SUM(PS.[used_page_count]) * 8 IndexSizeKB
	   ,IXUS.user_seeks AS NumOfSeeks
	   ,IXUS.user_scans AS NumOfScans
	   ,IXUS.user_lookups AS NumOfLookups
	   ,IXUS.user_updates AS NumOfUpdates
	   ,IXUS.last_user_seek AS LastSeek
	   ,IXUS.last_user_scan AS LastScan
	   ,IXUS.last_user_lookup AS LastLookup
	   ,IXUS.last_user_update AS LastUpdate
FROM sys.indexes IX
INNER JOIN sys.dm_db_index_usage_stats IXUS ON IXUS.index_id = IX.index_id AND IXUS.OBJECT_ID = IX.OBJECT_ID
INNER JOIN sys.dm_db_partition_stats PS on PS.object_id=IX.object_id
WHERE OBJECTPROPERTY(IX.OBJECT_ID,'IsUserTable') = 1
GROUP BY OBJECT_NAME(IX.OBJECT_ID) ,IX.name ,IX.type_desc ,IXUS.user_seeks ,IXUS.user_scans ,IXUS.user_lookups,IXUS.user_updates ,IXUS.last_user_seek ,IXUS.last_user_scan ,IXUS.last_user_lookup ,IXUS.last_user_update
-- Script to find unused or less used indexes in all tables of a SQL Server Database

USE [pwLegalOffice]; -- Change this to your database name
GO

;WITH IndexUsageStats AS (
    SELECT
        OBJECT_NAME(i.OBJECT_ID) AS TableName,
        i.name AS IndexName,
        SUM(user_seeks + user_scans + user_lookups) AS TotalReads,
        SUM(user_updates) AS TotalWrites,
        i.index_id,
        i.OBJECT_ID AS TableObjectId
    FROM
        sys.indexes AS i
    INNER JOIN
        sys.dm_db_index_usage_stats AS s ON i.OBJECT_ID = s.OBJECT_ID AND i.index_id = s.index_id
    WHERE
        OBJECTPROPERTY(i.OBJECT_ID, 'IsUserTable') = 1
        AND s.database_id = DB_ID() -- Ensure we're only looking at the current database
    GROUP BY
        i.OBJECT_ID, i.name, i.index_id
),
IndexPhysicalStats AS (
    SELECT
        OBJECT_NAME(OBJECT_ID) AS TableName,
        index_id,
        SUM(row_count) AS [RowCount],
        SUM(used_page_count) * 8 AS IndexSizeKB -- Convert pages to KB
    FROM
        sys.dm_db_partition_stats
    GROUP BY
        OBJECT_ID, index_id
)
SELECT
    u.TableName,
    u.IndexName,
    u.TotalReads,
    u.TotalWrites,
    p.[RowCount],
    p.IndexSizeKB
FROM
    IndexUsageStats AS u
LEFT JOIN
    IndexPhysicalStats AS p ON u.TableName = p.TableName AND u.index_id = p.index_id
WHERE
    u.TotalReads = 0 -- Indexes with zero reads
    OR u.TotalReads < u.TotalWrites -- Or, indexes with more writes than reads
ORDER BY
    u.TableName,
    u.IndexName;

Leave a Reply

Your email address will not be published.