Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
db.name AS databaseName
ps.OBJECT_ID AS objectID
ps.index_id AS indexID
ps.partition_number AS partitionNumber
ps.avg_fragmentation_in_percent AS fragmentation
ps.page_count
FROM sys.databases db
INNER JOIN sys.dm_db_index_physical_stats (NULL, NULL, NULL , NULL, N'Limited'
) ps
ON db.database_id = ps.database_id
WHERE ps.index_id > 0
AND ps.page_count > 100
AND ps.avg_fragmentation_in_percent > 30
OPTION (MaxDop 1);
,
,
,
,
,
, @executeSQL
BIT
= 1
/* 1 = execute; 0 = print command only */
, @DATABASE
VARCHAR(128)
= Null
/* Option to specify a database name; null will return all */
, @tableName
VARCHAR(4000) = Null -- databaseName.schema.table
Name
/* Option to specify a table name; null will return all */
, @onlineRebuild
BIT
= 1
/* 1 = online rebuild; 0 = offline rebuild; only in Enterprise */
, @maxDopRestriction
TINYINT
= Null
/* Option to restrict the number of processors for the operation; only i
n Enterprise */
, @printCommands
BIT
= 0
/* 1 = print commands; 0 = do not print commands */
, @printFragmentation BIT
= 0
/* 1 = print fragmentation prior to defrag;
0 = do not print */
, @defragDelay
CHAR(8)
= '00:00:05'
/* time to wait between defrag commands */
, @scanMode
NVARCHAR(8)
= N'Limited'
/* scan level to be used with dm_db_index_physical_stats. Options are DE
FAULT, NULL, LIMITED, SAMPLED, or DETAILED. The default (NULL) is LIMITED */
, @debugMode
BIT
= 0
/* display some useful comments to help determine if/where issues occur
*/
AS
/*******************************************************************************
**
Name:
dba_indexDefrag_sp
Author:
Purpose:
Notes:
CAUTION: TRANSACTION LOG SIZE MUST BE MONITORED CLOSELY WHEN DEFRAGMENTING.
@minFragmentation
@rebuildThreshold
@executeSQL
@database
@tableName
me;
if not specified, all tables will be defragged.
@onlineRebuild
1 = online rebuild;
0 = offline rebuild
@maxDopRestriction
ds
@printCommands
@printFragmentation
@defragDelay
@scanMode
s.
Options are DEFAULT, NULL, LIMITED, SAMPLED, or
DETAILED. The default (NULL) is LIMITED
@debugMode
ng
0 = do not display debug comments
Called by: SQL Agent Job or DBA
Date
Initials
Description
---------------------------------------------------------------------------2008-10-27 MFU
Initial Release for public consumption
2008-11-17 MFU
Added page-count to log table
, added @printFragmentation option
2009-03-17 MFU
Provided support for centralized execution,
, consolidated Enterprise & Standard versions
, added @debugMode, @maxDopRestriction
, modified LOB and partition logic
2009-05-12 JAP
Added @scanMode
********************************************************************************
*
Exec dbo.dba_indexDefrag_sp
@executeSQL
= 0
, @minFragmentation
= 80
, @printCommands
= 1
, @debugMode
= 1
, @printFragmentation = 1
, @database
= 'AdventureWorks'
, @tableName
= 'AdventureWorks.Sales.SalesOrderDetail';
********************************************************************************
*/
SET NOCOUNT ON;
SET XACT_Abort ON;
SET Quoted_Identifier ON;
BEGIN
IF @debugMode = 1 RAISERROR('Dusting off the spiderwebs and starting up...',
0, 42) WITH NoWait;
/* Declare our variables */
DECLARE @objectID
, @databaseID
, @databaseName
, @indexID
, @partitionCount
INT
INT
NVARCHAR(128)
INT
BIGINT
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
@schemaName
@objectName
@indexName
@partitionNumber
@partitions
@fragmentation
@pageCount
@sqlCommand
@rebuildCommand
@dateTimeStart
@dateTimeEnd
@containsLOB
@editionCheck
@debugMessage
@updateSQL
@partitionSQL
@partitionSQL_Param
@LOB_SQL
@LOB_SQL_Param
NVARCHAR(128)
NVARCHAR(128)
NVARCHAR(128)
SMALLINT
SMALLINT
FLOAT
INT
NVARCHAR(4000)
NVARCHAR(200)
DATETIME
DATETIME
BIT
BIT
VARCHAR(128)
NVARCHAR(4000)
NVARCHAR(4000)
NVARCHAR(1000)
NVARCHAR(4000)
NVARCHAR(1000);
Null
Null
Null
INT
VARCHAR(128)
INT
INT
, Null AS 'indexName'
FROM sys.dm_db_index_physical_stats (@databaseID, OBJECT_ID(@tableName),
Null , Null, @scanMode)
WHERE avg_fragmentation_in_percent >= @minFragmentation
And index_id > 0 -- ignore heaps
And page_count > 8 -- ignore objects with less than 1 extent
OPTION (MaxDop 1);
DELETE FROM #databaseList
WHERE databaseID = @databaseID;
END
CREATE CLUSTERED INDEX CIX_temp_indexDefragList
ON #indexDefragList(databaseID, objectID, indexID, partitionNumber);
SELECT @debugMessage = 'Looping through our list... there''s ' + CAST(COUNT(
*) AS VARCHAR(10)) + ' indexes to defrag!'
FROM #indexDefragList;
IF @debugMode = 1 RAISERROR(@debugMessage, 0, 42) WITH NoWait;
/* Begin our loop for defragging */
WHILE (SELECT COUNT(*) FROM #indexDefragList WHERE defragStatus = 0) > 0
BEGIN
IF @debugMode = 1 RAISERROR(' Picking an index to beat into shape...',
0, 42) WITH NoWait;
/* Grab the most fragmented index first to defrag */
SELECT TOP 1
@objectID
= objectID
, @indexID
= indexID
, @databaseID
= databaseID
, @databaseName
= databaseName
, @fragmentation
= fragmentation
, @partitionNumber = partitionNumber
, @pageCount
= page_count
FROM #indexDefragList
WHERE defragStatus = 0
ORDER BY fragmentation DESC;
IF @debugMode = 1 RAISERROR(' Looking up the specifics for our index...
', 0, 42) WITH NoWait;
/* Look up index information */
SELECT @updateSQL = N'Update idl
Set schemaName = QuoteName(s.name)
, objectName = QuoteName(o.name)
, indexName = QuoteName(i.name)
From #indexDefragList As idl
Inner Join ' + @databaseName + '.sys.objects As o
On idl.objectID = o.object_id
Inner Join ' + @databaseName + '.sys.indexes As i
On o.object_id = i.object_id
Inner Join ' + @databaseName + '.sys.schemas As s
On o.schema_id = s.schema_id
Where o.object_id = ' + CAST(@objectID AS VARCHAR(10)) + '
And i.index_id = ' + CAST(@indexID AS VARCHAR(10)) + '
And i.type > 0
ze';
/* If our index is partitioned, we should always reorganize */
IF @partitionCount > 1
SET @sqlCommand = @sqlCommand + N' Partition = '
+ CAST(@partitionNumber AS NVARCHAR(10));
END;
/* If the index is heavily fragmented and doesn't contain any partitions
or LOB's, rebuild it */
IF @fragmentation >= @rebuildThreshold And IsNull(@containsLOB, 0)
!= 1 And @partitionCount <= 1
BEGIN
/* Set online rebuild options; requires Enterprise Edition */
IF @onlineRebuild = 1 And @editionCheck = 1
SET @rebuildCommand = N' Rebuild With (Online = On';
ELSE
SET @rebuildCommand = N' Rebuild With (Online = Off';
/* Set processor restriction options; requires Enterprise Edition */
IF @maxDopRestriction IS Not Null And @editionCheck = 1
SET @rebuildCommand = @rebuildCommand + N', MaxDop = ' + CAST(@m
axDopRestriction AS VARCHAR(2)) + N')';
ELSE
SET @rebuildCommand = @rebuildCommand + N')';
SET @sqlCommand = N'Alter Index ' + @indexName + N' On ' + @database
Name + N'.'
+ @schemaName + N'.' + @objectName + @rebuildCommand
;
END;
/* Are we executing the SQL? If so, do it */
IF @executeSQL = 1
BEGIN
IF @debugMode = 1 RAISERROR(' Executing SQL statements...', 0, 42)
WITH NoWait;
/* Grab the time for logging purposes */
SET @dateTimeStart = GETDATE();
EXECUTE SP_EXECUTESQL @sqlCommand;
SET @dateTimeEnd = GETDATE();
/* Log our actions */
INSERT INTO dbo.dba_indexDefragLog
(
databaseID
, databaseName
, objectID
, objectName
, indexID
, indexName
, partitionNumber
, fragmentation
, page_count
, dateTimeStart
, durationSeconds
)
SELECT
@databaseID
, @databaseName
, @objectID
, @objectName
, @indexID
, @indexName
, @partitionNumber
, @fragmentation
, @pageCount
, @dateTimeStart
, DATEDIFF(SECOND, @dateTimeStart, @dateTimeEnd);
/* Just a little breather for the server */
WAITFOR Delay @defragDelay;
/* Print if specified to do so */
IF @printCommands = 1
PRINT N'Executed: ' + @sqlCommand;
END
ELSE
/* Looks like we're not executing, just printing the commands */
BEGIN
IF @debugMode = 1 RAISERROR(' Printing SQL statements...', 0, 42) W
ITH NoWait;
IF @printCommands = 1 PRINT IsNull(@sqlCommand, 'error!');
END
IF @debugMode = 1 RAISERROR(' Updating our index defrag status...', 0,
42) WITH NoWait;
/* Update our index defrag list so we know we've finished with that inde
x */
UPDATE #indexDefragList
SET defragStatus = 1
WHERE databaseID
=
And objectID
=
And indexID
=
And partitionNumber =
@databaseID
@objectID
@indexID
@partitionNumber;
END
/* Do we want to output our fragmentation results? */
IF @printFragmentation = 1
BEGIN
IF @debugMode = 1 RAISERROR(' Displaying fragmentation results...', 0,
42) WITH NoWait;
SELECT databaseID
, databaseName
, objectID
, objectName
, indexID
, indexName
, fragmentation
, page_count
FROM #indexDefragList;
END;
/* When everything is said and done, make sure to get rid of our temp table
*/
DROP TABLE #indexDefragList;
DROP TABLE #databaseList;
DROP TABLE #processor;
IF @debugMode = 1 RAISERROR('DONE! Thank you for taking care of your indexe
s! :)', 0, 42) WITH NoWait;
SET NOCOUNT OFF;
RETURN 0
END
GO