GO
IF EXISTS (SELECT job_id FROMmsdb.dbo.sysjobs_view WHEREname = N'Alert - UnusedIndexes')
EXEC msdb.dbo.sp_delete_job @job_name = N'Alert - UnusedIndexes', @delete_unused_schedule=1
GO
BEGIN TRANSACTION
DECLARE@ReturnCode INT
SELECT@ReturnCode = 0
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' ANDcategory_class=1)
BEGIN
EXEC@ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <>0) GOTOQuitWithRollback
END
DECLARE @jobId BINARY(16)
EXEC@ReturnCode = msdb.dbo.sp_add_job @job_name=N'Alert - UnusedIndexes',
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=2,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'This job runs every Monday morning at 07:33 and will email Chris@SQLServer365.co.uk if there are any indexes that are unused (0 reads) in any user database.',
@category_name=N'[Uncategorized (Local)]',
@owner_login_name=N'sa',
@notify_email_operator_name=N'Chris', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <>0) GOTOQuitWithRollback
/****** Object: Step [Get Unused Indexes] Script Date: 11/27/2012 14:42:49 ******/
EXEC@ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Get Unused Indexes',
@step_id=1,
@cmdexec_success_code=0,
@on_success_action=1,
@on_success_step_id=0,
@on_fail_action=2,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0, @subsystem=N'TSQL',
@command=N'-- Set database context
USE master;
GO
-- Declare variables
DECLARE @EmailProfile VARCHAR(255)
DECLARE @EmailRecipient VARCHAR(255)
DECLARE @EmailSubject VARCHAR(255)
DECLARE @IndexUsageStats INT
DECLARE @IndexCount INT
-- Get Index Usage History Stats Age
SET @IndexUsageStats = (SELECT DATEDIFF(DAY, sd.crdate, GETDATE()) AS days_history
FROM sys.sysdatabases sd
WHERE sd.[name] = ''tempdb'');
-- Set variables
SET @EmailProfile = ''DBA''
SET @EmailRecipient = ''Chris@SQLServer365.co.uk''
-- Drop temporary table if exists
IF OBJECT_ID(''tempDB.dbo.#UnusedIndexes'') IS NOT NULL
DROP TABLE #UnusedIndexes;
-- Create Temporary Table
CREATE TABLE #UnusedIndexes
(
DatabaseName VARCHAR(255) ,
TableName VARCHAR(1000) ,
IndexName VARCHAR(1000) ,
IndexID INT ,
TotalWrites BIGINT ,
TotalReads BIGINT ,
[Difference] BIGINT ,
DropScript VARCHAR(4000)
);
INSERT INTO #UnusedIndexes
EXEC sp_msforeachdb ''USE [?];
IF ''''?'''' NOT IN (''''master'''', ''''model'''',''''msdb'''', ''''tempdb'''', ''''ReportServer'''', ''''ReportServerTempDB'''', ''''Distribution'''')
BEGIN
SELECT DB_NAME(DB_ID()) ,
OBJECT_NAME(ddius.[object_id]) ,
i.name AS [IndexName] ,
i.index_id ,
user_updates AS [TotalWrites] ,
user_seeks + user_scans + user_lookups AS [TotalReads] ,
user_updates - ( user_seeks + user_scans + user_lookups ) AS [Difference] ,
''''USE '''' + ''''['''' + DB_NAME(DB_ID()) + ''''];'''' + '''' IF EXISTS (SELECT 1 FROM sys.indexes WHERE [object_id] = '''' + ''''object_id('''' + + '''''''''''''''' + ''''['''' + SCHEMA_NAME(o.[schema_id]) + ''''].'''' + ''''['''' + OBJECT_NAME(ddius.[object_id]) + '''']'''' + '''''''''''''''' + '''')'''' + '''' AND name = '''' + '''''''''''''''' + i.NAME + '''''''''''''''' + '''')''''
+ '''' DROP INDEX '''' + ''''['''' + i.name + '''']'''' + '''' ON '''' + ''''['''' + SCHEMA_NAME(o.[schema_id]) + ''''].'''' + ''''['''' + OBJECT_NAME(ddius.[object_id]) + ''''];''''
FROM sys.dm_db_index_usage_stats AS ddius WITH ( NOLOCK )
INNER JOIN sys.indexes AS i WITH ( NOLOCK ) ON ddius.[object_id] = i.[object_id]
AND i.index_id = ddius.index_id
INNER JOIN sys.objects AS o WITH ( NOLOCK ) ON i.[object_id] = o.[object_id]
WHERE OBJECTPROPERTY(ddius.[object_id], ''''IsUserTable'''') = 1 -- Only user tables
AND ddius.database_id = DB_ID() -- Current Database
AND ( user_seeks + user_scans + user_lookups ) = 0 -- 0 Reads
AND i.index_id > 1 -- Exclude clustered indexes and heaps
AND i.is_primary_key = 0 -- Exclude primary keys
AND i.is_unique = 0 -- Exclude unique indexes
ORDER BY [TotalReads] ASC;
END
''
-- Check for unused indexes
IF EXISTS ( SELECT 1
FROM #UnusedIndexes)
BEGIN
DECLARE @tableHTML NVARCHAR(MAX);
SET @tableHTML = N''<style type="text/css">''
+ N''.h1 {font-family: Arial, verdana;font-size:16px;border:0px;background-color:white;} ''
+ N''.h2 {font-family: Arial, verdana;font-size:12px;border:0px;background-color:white;} ''
+ N''body {font-family: Arial, verdana;} ''
+ N''table{font-size:12px; border-collapse:collapse;border:1px solid black; padding:3px;} ''
+ N''td{background-color:#F1F1F1; border:1px solid black; padding:3px;} ''
+ N''th{background-color:#99CCFF; border:1px solid black; padding:3px;}''
+ N''</style>'' + N''<table border="1">'' + N''<tr>''
+ N''<th>DatabaseName</th>''
+ N''<th>TableName</th>''
+ N''<th>IndexName</th>''
+ N''<th>IndexID</th>''
+ N''<th>TotalWrites</th>''
+ N''<th>TotalReads</th>''
+ N''<th>Difference</th>''
+ N''<th>DropScript</th>''
+ N''</tr>''
+ CAST(( SELECT td = DatabaseName,
'''',
td = TableName,
'''',
td = IndexName,
'''',
td = IndexID,
'''',
td = TotalWrites,
'''',
td = TotalReads,
'''',
td = [Difference],
'''',
td = DropScript,
''''
FROM #UnusedIndexes
FOR
XML PATH(''tr'') ,
TYPE
) AS NVARCHAR(MAX)) + N''</table>'';
-- Count Indexes
SELECT @IndexCount = COUNT(1) FROM #UnusedIndexes;
-- Set subject
SET @EmailSubject = ''ALERT - '' + CAST(@IndexCount AS VARCHAR(100)) + '' Unused Indexes found on '' + @@SERVERNAME + '' - have not been used for '' + CAST(@IndexUsageStats AS VARCHAR(100)) + '' days''
-- Email results
EXEC msdb.dbo.sp_send_dbmail @profile_name = @EmailProfile,
@recipients = @EmailRecipient, @subject = @EmailSubject,
@body = @tableHTML, @body_format = ''HTML'';
END
GO',
@database_name=N'master',
@flags=12
IF (@@ERROR <> 0 OR @ReturnCode <>0) GOTOQuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <>0) GOTOQuitWithRollback
EXEC@ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Monday at 07:33',
@enabled=1,
@freq_type=8,
@freq_interval=2,
@freq_subday_type=1,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=1,
@active_start_date=20121123,
@active_end_date=99991231,
@active_start_time=73300,
@active_end_time=235959
IF (@@ERROR <> 0 OR @ReturnCode <>0) GOTOQuitWithRollback
EXEC@ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <>0) GOTOQuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO