Blog Post

Storing sp_BlitzIndex to a Table Between Reboots

,

I mentioned in my New Database Job – The 90 Day Plan blog how I have a trick for storing index usage stats up until close to the next reboot of the SQL Server.  You really can do this for any DMV related query that you gets reset at the reboot of a SQL Server instance.  With this I am able to have data of the most the current index usage stats up to the midnight before a reboot of my SQL instances to analyze.

CREATE TABLE [dbo].[ServerStartupTimes](
[ID] [INT] IDENTITY(1,1) NOT NULL,
[sqlserver_start_time] [DATETIME] NOT NULL,
CONSTRAINT [PK_ServerStartupTimes] PRIMARY KEY CLUSTERED 
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY]
GO

Then at the in a SQL Agent Job I start it with the following code to check a table the table for the last startup time.  If the current startup time does not match the last recorded time the time it will insert the new time in the ServerStartupTimes table. If the time matches it will delete the last batch of data recorded from sp_BlitzIndex.

DECLARE @recorded_start_time DATETIME,
    @current_start_time DATETIME,
    @last_run_datetime DATETIME
SELECT TOP (1) @recorded_start_time = sqlserver_start_time 
FROM dbo.ServerStartupTimes 
ORDER BY ID DESC
SELECT @current_start_time = sqlserver_start_time 
FROM sys.dm_os_sys_info
IF @current_start_time <> @recorded_start_time OR @recorded_start_time IS NULL
BEGIN
    INSERT INTO dbo.ServerStartupTimes (sqlserver_start_time)
    VALUES (@current_start_time)
END
ELSE
BEGIN
    SELECT @last_run_datetime = MAX(run_datetime) 
    FROM dbo.BlitzIndex
    WHERE run_datetime > GETDATE() -2
    DELETE FROM dbo.BlitzIndex 
    WHERE run_datetime = @last_run_datetime
END

Next, we insert the data into the table we want to keep the index usage data in:

EXEC dbo.sp_BlitzIndex @Mode = 2, 
    @GetAllDatabases = 1, 
    @BringThePain = 1,
    @OutputDatabaseName = 'DBATools',
    @OutputSchemaName  = 'dbo',
    @OutputTableName = 'BlitzIndex'

Then I create an index on the run_datetime column if it doesn’t exist so I can cleanup data faster.

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_BlitzIndex_run_datetime')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_BlitzIndex_run_datetime] ON [dbo].[BlitzIndex]
    (
        [run_datetime] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
END

Finally, we can cleanup any data older than x number of days, I do 90 days:

DELETE FROM dbo.BlitzIndex
WHERE run_datetime <= GETDATE() - 90

Final script for the whole job is:

IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'ServerStartupTimes')
BEGIN
    CREATE TABLE [dbo].[ServerStartupTimes](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [sqlserver_start_time] [datetime] NOT NULL,
     CONSTRAINT [PK_ServerStartupTimes] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
END
GO
DECLARE @recorded_start_time DATETIME,
    @current_start_time DATETIME,
    @last_run_datetime DATETIME
SELECT TOP (1) @recorded_start_time = sqlserver_start_time 
FROM dbo.ServerStartupTimes 
ORDER BY ID DESC
SELECT @current_start_time = sqlserver_start_time 
FROM sys.dm_os_sys_info
IF @current_start_time <> @recorded_start_time OR @recorded_start_time IS NULL
BEGIN
    INSERT INTO dbo.ServerStartupTimes (sqlserver_start_time)
    VALUES (@current_start_time)
END
ELSE
BEGIN
    SELECT @last_run_datetime = MAX(run_datetime) 
    FROM dbo.BlitzIndex
    WHERE run_datetime > GETDATE() -2
    DELETE FROM dbo.BlitzIndex 
    WHERE run_datetime = @last_run_datetime
END
EXEC dbo.sp_BlitzIndex @Mode = 2, 
    @GetAllDatabases = 1, 
    @BringThePain = 1,
    @OutputDatabaseName = 'DBATools',
    @OutputSchemaName  = 'dbo',
    @OutputTableName = 'BlitzIndex'
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_BlitzIndex_run_datetime')
BEGIN
    CREATE NONCLUSTERED INDEX [IX_BlitzIndex_run_datetime] ON [dbo].[BlitzIndex]
    (
        [run_datetime] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
END
DELETE FROM dbo.BlitzIndex
WHERE run_datetime <= GETDATE() - 90

And with data I have the most up to the current index usage stats up to the midnight before a reboot of my SQL instances to analyze.

The post Storing sp_BlitzIndex to a Table Between Reboots first appeared on Tracy Boggiano's Blog.

Original post (opens in new tab)
View comments in original post (opens in new tab)

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating