INDEX DEFRAGMENTATION SCRIPT for 2008 / 2005
I dedicate this article to my senior DBA “Roshan Joe Joseph” who has helped me to write a script.
I have posted the updated INDEX DEFRAGMENTATION script here, which is already published in sqlservercentral (SSC).
Script changes:
· I used while loop instead of a cursor.
· I used to rebuild the index if the page level locking is disabled.
Msg 2552, Level 16, State 2, Line 1
The index “index name” (partition 1) on table “table name” cannot be reorganized because page level locking is disabled
Index Defragmentation is one of the most important DBA tasks. This will significantly improve query performance. When you perform any DML operation (INSERT, UPDATE, or DELETE statements) table fragmentation can occur. If you use predefined maintenance plan it will take much server resource and time. Here is a custom stored procedure.
If you want to determine the level of fragmentation, you can use the SYS.DM_DB_INDEX_PHYSICAL_STATS statement. The SYS.DM_DB_INDEX_PHYSICAL_STATS DMV displays fragmentation information for the data and indexes of the specified object.
Here I used 4 conditions:
1. Fragmentation >=30 AND PAGES>1000 then rebuild
2. Fragmentation between 15 to 29 AND PAGES>1000 then reorganize & update statistics
3. If the page level locking is disabled then rebuild
4. If the above conditions are false and statistics are outdated more than 10 days then update the statistics
Before you run the procedure create the tables provided for history propose
Read Gail Shaw’s post ‘What is fragmentation’ and how it will affect the performance http://sqlinthewild.co.za/index.php/2008/10/20/what-is-fragmentation/
-- For SQL-2005/2008 USE MSDB; go CREATE TABLE [dbo].[dba_defrag_maintenance_history] ( [db_name] [SYSNAME] NOT NULL, [table_name] [SYSNAME] NOT NULL, [index_name] [SYSNAME] NOT NULL, [frag] [FLOAT] NULL, [page] [INT] NULL, [action_taken] [VARCHAR](35) NULL, [last_stats_date] [datetime] NULL, [date] [DATETIME] NULL DEFAULT (GETDATE()) ) go --Archive the data's in master DB USE MASTER; go CREATE TABLE [dbo].[dba_defrag_maintenance_history] ( [db_name] [SYSNAME] NOT NULL, [table_name] [SYSNAME] NOT NULL, [index_name] [SYSNAME] NOT NULL, [frag] [FLOAT] NULL, [page] [INT] NULL, [action_taken] [VARCHAR](35) NULL, [last_stats_date] [datetime] NULL, [date] [DATETIME] NULL DEFAULT (GETDATE()) ) go USE [msdb] GO /****** Object: StoredProcedure [dbo].[indexdefragmentation] Script Date: 09/07/2012 05:18:52 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO --drop proc [indexdefragmentation] CREATE PROC [dbo].[indexdefragmentation]@p_dbname SYSNAME /* Summary: Remove the Index Fragmentation to improve the query performance Contact: Muthukkumaran Kaliyamoorhty SQL DBA Description: This Sproc will take the fragmentation details and do four kinds of work. 1. Check the fragmentation greater than 30% and pages greater than 1000 then rebuild 2. Check the fragmentation between 5% to 30% and pages greater than 1000 then reorganize & update stats 3. Check the fragmentation between 5% to 30% and pages greater than 1000 and page level lock disabled then rebuild 4. Update the statistics if the above conditions are false /*statistics will be updated if its gets 10 days older */ ChangeLog: Date Coder Description 2012-sep-7 Muthukkumaran Kaliyamoorhty created 2012-sep-8 Muthukkumaran Kaliyamoorhty updates Stats date *************************All the SQL keywords should be written in upper case************************* */ AS BEGIN SET NOCOUNT ON DECLARE @db_name SYSNAME, @tab_name SYSNAME, @ind_name VARCHAR(500), @schema_name SYSNAME, @frag FLOAT, @pages INT, @min_id INT, @max_id INT, @stats_date VARCHAR(8) SET @db_name=@p_dbname -------------------------------------------------------------------------------------------------------------------------------------- --inserting the Fragmentation details -------------------------------------------------------------------------------------------------------------------------------------- CREATE TABLE #tempfrag ( id INT IDENTITY, table_name SYSNAME, index_name VARCHAR(500), frag FLOAT, pages INT, schemaName SYSNAME, statsDate VARCHAR(8) ) EXEC ('USE ['+@db_name+']; INSERT INTO #tempfrag (table_name,index_name,frag,pages,schemaName,statsDate) SELECT OBJECT_NAME(F.OBJECT_ID) obj,i.name ind, f.avg_fragmentation_in_percent, f.page_count,OBJECT_SCHEMA_NAME(f.object_id), CONVERT(VARCHAR(8),STATS_DATE(I.OBJECT_ID,I.index_id),112)as statsdate FROM SYS.DM_DB_INDEX_PHYSICAL_STATS (DB_ID(),NULL,NULL,NULL,NULL) F JOIN SYS.INDEXES I ON(F.OBJECT_ID=I.OBJECT_ID)AND i.index_id=f.index_id JOIN INFORMATION_SCHEMA.TABLES S ON (s.table_name=OBJECT_NAME(F.OBJECT_ID)) AND f.database_id=DB_ID() AND OBJECTPROPERTY(I.OBJECT_ID,''ISSYSTEMTABLE'')=0 AND alloc_unit_type_desc = ''IN_ROW_DATA'' AND is_disabled = 0 ' ) SELECT @min_id=MIN(ID)FROM #tempfrag SELECT @max_id=MAX(ID)FROM #tempfrag TRUNCATE TABLE msdb.dbo.dba_defrag_maintenance_history --SELECT * FROM #tempfrag WHILE (@min_id<=@max_id) /*While loop begin*/ BEGIN SELECT @tab_name=table_name, @schema_name=schemaname, @ind_name=index_name , @frag=frag , @pages=pages, @stats_date=statsDate FROM #tempfrag WHERE id = @min_id -------------------------------------------------------------------------------------------------------------------------------------- --Check the fragmentation greater than 30% and pages greater than 1000 then rebuild -------------------------------------------------------------------------------------------------------------------------------------- IF (@ind_name IS NOT NULL) /*First if condition*/ BEGIN IF (@frag>30 AND @pages>1000) /*Sub if condition 1st */ BEGIN EXEC ('USE ['+@db_name+'];ALTER INDEX ['+@ind_name+'] ON ['+@schema_name+'].['+@tab_name +'] REBUILD ') INSERT INTO msdb.dbo.dba_defrag_maintenance_history VALUES (@db_name,@tab_name,@ind_name,@frag,@pages,'REBUILD',@stats_date,GETDATE()) END -------------------------------------------------------------------------------------------------------------------------------------- --Check the fragmentation between 5% to 30% and pages greater than 1000 then reorganize -------------------------------------------------------------------------------------------------------------------------------------- ELSE IF((@frag BETWEEN 5 AND 30) AND @pages>1000 ) /*Sub if condition 2nd */ BEGIN BEGIN TRY EXEC ('USE ['+@db_name+'];ALTER INDEX ['+@ind_name+'] ON ['+@schema_name+'].['+@tab_name +'] REORGANIZE ') IF (@stats_date <CONVERT(VARCHAR(8),DATEADD(HH,1,GETDATE()-10),112)) BEGIN EXEC ('USE ['+@db_name+'];UPDATE STATISTICS ['+@schema_name+'].['+@tab_name+'] (['+@ind_name+']) ' ) INSERT INTO msdb.dbo.dba_defrag_maintenance_history VALUES (@db_name,@tab_name,@ind_name,@frag,@pages,'REORGANIZE & UPDATESTATS',@stats_date,GETDATE()) END END TRY BEGIN CATCH -------------------------------------------------------------------------------------------------------------------------------------- --Check the fragmentation between 15% to 29% and pages greater than 1000 and page level --lock disabled then rebuild -------------------------------------------------------------------------------------------------------------------------------------- IF ERROR_NUMBER()=2552 EXEC ('USE ['+@db_name+'];ALTER INDEX ['+@ind_name+'] ON ['+@schema_name+'].['+@tab_name +'] REBUILD ') INSERT INTO msdb.dbo.dba_defrag_maintenance_history VALUES (@db_name,@tab_name,@ind_name,@frag,@pages,'PLLD_REBUILD',@stats_date,GETDATE()) END CATCH END -------------------------------------------------------------------------------------------------------------------------------------- --Update the statistics for all indexes if the first three conditions is false -------------------------------------------------------------------------------------------------------------------------------------- /*Sub if condition 3rd*/ ELSE BEGIN IF (@stats_date < CONVERT(VARCHAR(8),DATEADD(HH,1,GETDATE()-10),112)) BEGIN EXEC ('USE ['+@db_name+'];UPDATE STATISTICS ['+@schema_name+'].['+@tab_name+'] (['+@ind_name+']) ' ) INSERT INTO msdb.dbo.dba_defrag_maintenance_history VALUES (@db_name,@tab_name,@ind_name,@frag,@pages,'UPDATESTATS',@stats_date,GETDATE()) END END END ELSE BEGIN IF (@stats_date < CONVERT(VARCHAR(8),DATEADD(HH,1,GETDATE()-10),112)) BEGIN -------------------------------------------------------------------------------------------------------------------------------------- --Update the statistics for all tables if the first three conditions is false -------------------------------------------------------------------------------------------------------------------------------------- EXEC ('USE ['+@db_name+'];UPDATE STATISTICS ['+@schema_name+'].['+@tab_name+']') INSERT INTO msdb.dbo.dba_defrag_maintenance_history VALUES (@db_name,@tab_name,'HEAP',@frag,@pages,'UPDATESTATS',@stats_date,GETDATE()) END /*End of the first if condition*/ END SET @min_id=@min_id+1 /*While loop end*/ END DROP TABLE #tempfrag INSERT INTO master.dbo.dba_defrag_maintenance_history SELECT * FROM msdb.dbo.dba_defrag_maintenance_history END GO
12 Comments
vinothkumar.s
Muthu,
index defragmentation script is nice one.i ll check the script in one of my server and let u know(i am using M.P only).I am really appreciate you learned/wrote a scripts…keep up the good work.
Anonymous
muthukkuaran,
Nice Script.its helped me thanks.
muthukkumaran
@vino,Thanks I'll keep post it.
Anonymous
Muthu,
I need a script for sql 2000 servers.
Balaji,
(remember me)
Muthukkumaran Kaliyamoorthy
@Balaji,
Yep, I will post it.Meanwhile you can search SSC-SQLservercentral
Anonymous
Muthu,
I searched in SSC the scripts available only for 2005 and 2008.
Muthukkumaran Kaliyamoorthy
index defragmentation script for sql server 2000
http://sqlserverblogforum.blogspot.com/2011/03/index-defragmentation-script-for-sql.html
Pingback:
Pingback:
Van
Very interesting details you have mentioned, thank you for posting.
Muthukkumaran kaliyamoorthy
Van,
i am glad you liked it.
google cloud platform training
muthukkuaran,
Nice Script.its helped me thanks.