peterh3244
Programmer
Background
Recently index corruption has been occuring on one of our datebase tables.
Basically when trying to execute a select statement which orders by date only entries show that were entered on the day of corruption. Without the order by clause all data appears to be returned, but obviously not in the order we want it. To fix the problem we have to delete all that days ‘inserts’ and then re-create the indexes on the table. Finally the the data for that day is re-inserted into the table. Everything is fine for about three months and then the problem occurs again.
Investigation has established that the disk that the MDF resides on is 89% defragmented and the attempt at defraging it were unsuccessful. The LOG resides on another disk and again was fragmented at 50%, defragmentation of this disk was unsuccessfull.
During the investigation we created a SQL job that was supposed to alert us of table indexes that need defraging. Once defraged, the job was run again. This time not only indexes that were fragmented were re-reported BUT other indexes that were reported as OK were now being reported at fragmentation levels of above 30%.
As a number of unexpected results occurred during the index investigation I have documented it with any Questions we have.
Any answers to the question would be gratefully received as would any theories on why what has happened as happended
15/02/2011
1) The defrag index program was modified to create the frag table permanently to allow analysis of any voyager fragmented indexes.
2) The index defrag program was run (see Appendix A).
3) The table YesterdaysDiaries was reported as having indexes that fragmented over thirty percent,
4) The table YesterdaysDiaries was defraged using the command given.
5) The defrag index program was run again and although the database was not in use, not only was the table YesterdaysDiaries reported as being in need of defragmentation (which means the defrag had no affect maybe!) but other indexes of tables were reported as needing to be defraged. 4 tables in all.
6) The disks holding the database and log files required were defragmented.
7) There was no problem defragmenting the disk holding the log file.
8) However there was a problem defragmenting the disk holding the MDF file.
9) Therefore the database was shrunk. Using the SHRINK command. Four gigabytes was removed from the database.
10) Still the disk holding the MDF file could not be defraged.
11) MDF file was then copied to a scratch drive (and then deleted) from the disk to be defraged.
12) The disk was then defragmented successfully
13) MDF file then was copied back to the disk. Note the dragmentor still reported that MDF file was fragmented in 7 places However defragmentration was still a success!
14) The defrag program for indexes was again run
15) This time there were about 300 or more indexes returned as being defragmented.
16/2/2011
1. Correct all the defrag issues using recommeded command
2. UPDATE STATISTICS APPLIED for all tables using sp_updatestats
3. Re-run the defrag job.
4. Obsevered that although some table indexes which where reported as fragmented there were a less of these than before. Now 239 indexs out 994 are fragmented (24%). 24% of indexes are still fragmented
6. Backup database
Questions to answer
1. Does creating and dropping a new table (frag) cause fragmentation of the indexes. Would this be proved by modifying the program to create the frag table in a completely different database?
2. Why did the defraging command have no effect on YesterdaysDiaries?
3. Did the defragmentation of the disk cause 300 odd indexes to be fragmented?
4. OR was this fragmentation caused by the running of the SHRINK command.
5. Was the update statistics responsible for the reduction in the number of the indexes reported as fragmented?
Appendix A
CREATE PROCEDURE sp_Defrag
AS
SET NOCOUNT ON
DECLARE @tablename VARCHAR (128)
DECLARE @execstr VARCHAR (255)
DECLARE @objectid INT
DECLARE @indexid INT
DECLARE @frag DECIMAL
DECLARE @maxfrag DECIMAL
DECLARE @NAME VARCHAR(512)
DECLARE @BUF VARCHAR(8000)
declare @msg1 varchar(255)
declare @msg2 varchar(255)
-- Decide on the maximum fragmentation to allow
SELECT @maxfrag = 30.0
-- Declare cursor
DECLARE tables CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[fraglist]')
and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE fraglist
END
-- Create the table
CREATE TABLE FRAGLIST (
ObjectName CHAR (255),
ObjectId INT,
IndexName CHAR (255),
IndexId INT,
Lvl INT,
CountPages INT,
CountRows INT,
MinRecSize INT,
MaxRecSize INT,
AvgRecSize INT,
ForRecCount INT,
Extents INT,
ExtentSwitches INT,
AvgFreeBytes INT,
AvgPageDensity INT,
ScanDensity DECIMAL,
BestCount INT,
ActualCount INT,
LogicalFrag DECIMAL,
ExtentFrag DECIMAL)
-- Open the cursor
OPEN tables
select @@servername
-- Loop through all the tables in the database
FETCH NEXT
FROM tables
INTO @tablename
WHILE @@FETCH_STATUS = 0
BEGIN
-- Do the showcontig of all indexes of the table
INSERT INTO FRAGLIST
EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''')
WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS')
FETCH NEXT
FROM tables
INTO @tablename
END
-- Close and deallocate the cursor
CLOSE tables
DEALLOCATE tables
-- Declare cursor for list of indexes to be defragged
DECLARE indexes CURSOR FOR
SELECT ObjectName, ObjectId, IndexId, LogicalFrag
FROM FRAGLIST
WHERE LogicalFrag >= @maxfrag
AND INDEXPROPERTY (ObjectId, IndexName, 'IndexDepth') > 0
-- Open the cursor
OPEN indexes
-- loop through the indexes
FETCH NEXT
FROM indexes
INTO @tablename, @objectid, @indexid, @frag
set @Buf = @@servername + ' The Database is Fragmented.'
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @name =[name] FROM [dbo].[sysobjects]
where id = RTRIM(@objectid)
SELECT @execstr = 'DBCC INDEXDEFRAG (0, ' + RTRIM(@objectid) + ',
' + RTRIM(@indexid) + ')'
set @msg1 = @execstr + ' -- (' + @NAME + ') ' + ' fragmented by ' + RTRIM(CONVERT(varchar(15),@frag)) + '%'
IF LEN(@BUF + CHAR(13) +CHAR(10) + ' ') >= 8000
BEGIN
set @msg2 = 'Database Status on' + @@Servername
EXEC master..xp_sendmail @recipients = '',
@copy_recipients = '*********',
@subject = @msg2,
@message = @BUF
set @buf = @@servername + ' The Voyager Database is Fragmented.' + CHAR(13) + CHAR(10) + ' ' + @msg1
END
ELSE
BEGIN
set @buf = @buf + CHAR(13) + CHAR(10) + ' ' + @MSG1
END
FETCH NEXT
FROM indexes
INTO @tablename, @objectid, @indexid, @frag
END
EXEC master..xp_sendmail @recipients = '****************',
@copy_recipients = '*****************',
@subject = @msg2,
@message = @BUF
-- Close and deallocate the cursor
CLOSE indexes
DEALLOCATE indexes
Many thanks Peter
Recently index corruption has been occuring on one of our datebase tables.
Basically when trying to execute a select statement which orders by date only entries show that were entered on the day of corruption. Without the order by clause all data appears to be returned, but obviously not in the order we want it. To fix the problem we have to delete all that days ‘inserts’ and then re-create the indexes on the table. Finally the the data for that day is re-inserted into the table. Everything is fine for about three months and then the problem occurs again.
Investigation has established that the disk that the MDF resides on is 89% defragmented and the attempt at defraging it were unsuccessful. The LOG resides on another disk and again was fragmented at 50%, defragmentation of this disk was unsuccessfull.
During the investigation we created a SQL job that was supposed to alert us of table indexes that need defraging. Once defraged, the job was run again. This time not only indexes that were fragmented were re-reported BUT other indexes that were reported as OK were now being reported at fragmentation levels of above 30%.
As a number of unexpected results occurred during the index investigation I have documented it with any Questions we have.
Any answers to the question would be gratefully received as would any theories on why what has happened as happended
15/02/2011
1) The defrag index program was modified to create the frag table permanently to allow analysis of any voyager fragmented indexes.
2) The index defrag program was run (see Appendix A).
3) The table YesterdaysDiaries was reported as having indexes that fragmented over thirty percent,
4) The table YesterdaysDiaries was defraged using the command given.
5) The defrag index program was run again and although the database was not in use, not only was the table YesterdaysDiaries reported as being in need of defragmentation (which means the defrag had no affect maybe!) but other indexes of tables were reported as needing to be defraged. 4 tables in all.
6) The disks holding the database and log files required were defragmented.
7) There was no problem defragmenting the disk holding the log file.
8) However there was a problem defragmenting the disk holding the MDF file.
9) Therefore the database was shrunk. Using the SHRINK command. Four gigabytes was removed from the database.
10) Still the disk holding the MDF file could not be defraged.
11) MDF file was then copied to a scratch drive (and then deleted) from the disk to be defraged.
12) The disk was then defragmented successfully
13) MDF file then was copied back to the disk. Note the dragmentor still reported that MDF file was fragmented in 7 places However defragmentration was still a success!
14) The defrag program for indexes was again run
15) This time there were about 300 or more indexes returned as being defragmented.
16/2/2011
1. Correct all the defrag issues using recommeded command
2. UPDATE STATISTICS APPLIED for all tables using sp_updatestats
3. Re-run the defrag job.
4. Obsevered that although some table indexes which where reported as fragmented there were a less of these than before. Now 239 indexs out 994 are fragmented (24%). 24% of indexes are still fragmented
6. Backup database
Questions to answer
1. Does creating and dropping a new table (frag) cause fragmentation of the indexes. Would this be proved by modifying the program to create the frag table in a completely different database?
2. Why did the defraging command have no effect on YesterdaysDiaries?
3. Did the defragmentation of the disk cause 300 odd indexes to be fragmented?
4. OR was this fragmentation caused by the running of the SHRINK command.
5. Was the update statistics responsible for the reduction in the number of the indexes reported as fragmented?
Appendix A
CREATE PROCEDURE sp_Defrag
AS
SET NOCOUNT ON
DECLARE @tablename VARCHAR (128)
DECLARE @execstr VARCHAR (255)
DECLARE @objectid INT
DECLARE @indexid INT
DECLARE @frag DECIMAL
DECLARE @maxfrag DECIMAL
DECLARE @NAME VARCHAR(512)
DECLARE @BUF VARCHAR(8000)
declare @msg1 varchar(255)
declare @msg2 varchar(255)
-- Decide on the maximum fragmentation to allow
SELECT @maxfrag = 30.0
-- Declare cursor
DECLARE tables CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[fraglist]')
and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE fraglist
END
-- Create the table
CREATE TABLE FRAGLIST (
ObjectName CHAR (255),
ObjectId INT,
IndexName CHAR (255),
IndexId INT,
Lvl INT,
CountPages INT,
CountRows INT,
MinRecSize INT,
MaxRecSize INT,
AvgRecSize INT,
ForRecCount INT,
Extents INT,
ExtentSwitches INT,
AvgFreeBytes INT,
AvgPageDensity INT,
ScanDensity DECIMAL,
BestCount INT,
ActualCount INT,
LogicalFrag DECIMAL,
ExtentFrag DECIMAL)
-- Open the cursor
OPEN tables
select @@servername
-- Loop through all the tables in the database
FETCH NEXT
FROM tables
INTO @tablename
WHILE @@FETCH_STATUS = 0
BEGIN
-- Do the showcontig of all indexes of the table
INSERT INTO FRAGLIST
EXEC ('DBCC SHOWCONTIG (''' + @tablename + ''')
WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS')
FETCH NEXT
FROM tables
INTO @tablename
END
-- Close and deallocate the cursor
CLOSE tables
DEALLOCATE tables
-- Declare cursor for list of indexes to be defragged
DECLARE indexes CURSOR FOR
SELECT ObjectName, ObjectId, IndexId, LogicalFrag
FROM FRAGLIST
WHERE LogicalFrag >= @maxfrag
AND INDEXPROPERTY (ObjectId, IndexName, 'IndexDepth') > 0
-- Open the cursor
OPEN indexes
-- loop through the indexes
FETCH NEXT
FROM indexes
INTO @tablename, @objectid, @indexid, @frag
set @Buf = @@servername + ' The Database is Fragmented.'
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @name =[name] FROM [dbo].[sysobjects]
where id = RTRIM(@objectid)
SELECT @execstr = 'DBCC INDEXDEFRAG (0, ' + RTRIM(@objectid) + ',
' + RTRIM(@indexid) + ')'
set @msg1 = @execstr + ' -- (' + @NAME + ') ' + ' fragmented by ' + RTRIM(CONVERT(varchar(15),@frag)) + '%'
IF LEN(@BUF + CHAR(13) +CHAR(10) + ' ') >= 8000
BEGIN
set @msg2 = 'Database Status on' + @@Servername
EXEC master..xp_sendmail @recipients = '',
@copy_recipients = '*********',
@subject = @msg2,
@message = @BUF
set @buf = @@servername + ' The Voyager Database is Fragmented.' + CHAR(13) + CHAR(10) + ' ' + @msg1
END
ELSE
BEGIN
set @buf = @buf + CHAR(13) + CHAR(10) + ' ' + @MSG1
END
FETCH NEXT
FROM indexes
INTO @tablename, @objectid, @indexid, @frag
END
EXEC master..xp_sendmail @recipients = '****************',
@copy_recipients = '*****************',
@subject = @msg2,
@message = @BUF
-- Close and deallocate the cursor
CLOSE indexes
DEALLOCATE indexes
Many thanks Peter