<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Updated Index Defrag Script (2005, 2008)</title>
	<atom:link href="http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/feed/" rel="self" type="application/rss+xml" />
	<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/</link>
	<description>Adventures in SQL Tuning - a blog for the rest of us</description>
	<lastBuildDate>Tue, 07 Feb 2012 21:28:07 -0700</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
	<item>
		<title>By: Index Defragmentation &#171; dbadiary</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-5839</link>
		<dc:creator>Index Defragmentation &#171; dbadiary</dc:creator>
		<pubDate>Sat, 14 May 2011 02:51:38 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-5839</guid>
		<description>[...] is sophisticated Index Defrag and Rebuild SP, by Michelle Ufford, which does the job automatically; you just need to plug the values to the [...]</description>
		<content:encoded><![CDATA[<p>[...] is sophisticated Index Defrag and Rebuild SP, by Michelle Ufford, which does the job automatically; you just need to plug the values to the [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-5140</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Mon, 17 May 2010 21:03:55 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-5140</guid>
		<description>@Slick Check out the latest version at: http://sqlfool.com/2010/04/index-defrag-script-v4-0/.  Among (many) other features, the updated version allows you to defrag multiple databases by calling just the one job.  I usually put the proc in an admin database and call it from there.</description>
		<content:encoded><![CDATA[<p>@Slick Check out the latest version at: <a href="http://sqlfool.com/2010/04/index-defrag-script-v4-0/" rel="nofollow">http://sqlfool.com/2010/04/index-defrag-script-v4-0/</a>.  Among (many) other features, the updated version allows you to defrag multiple databases by calling just the one job.  I usually put the proc in an admin database and call it from there.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Slick</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-5139</link>
		<dc:creator>Slick</dc:creator>
		<pubDate>Mon, 17 May 2010 20:35:22 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-5139</guid>
		<description>Hi Michelle, 

Thank you for the great stored procedure. I have a question. I have about 3 databases I need to run this in on the same server. Does this mean I have to put this stored procedure and table within each DB or just the master DB.

I want to be able to run this as a scheduled SQL job. Please let me know.

Thanks,
Slick</description>
		<content:encoded><![CDATA[<p>Hi Michelle, </p>
<p>Thank you for the great stored procedure. I have a question. I have about 3 databases I need to run this in on the same server. Does this mean I have to put this stored procedure and table within each DB or just the master DB.</p>
<p>I want to be able to run this as a scheduled SQL job. Please let me know.</p>
<p>Thanks,<br />
Slick</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-1617</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Mon, 16 Mar 2009 23:19:41 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-1617</guid>
		<description>Hi Nathan!  I&#039;m actually working on a revision to my script that will include the option to specify a database name.  I&#039;m almost done, I hope to have it up sometime this week.  :)</description>
		<content:encoded><![CDATA[<p>Hi Nathan!  I&#8217;m actually working on a revision to my script that will include the option to specify a database name.  I&#8217;m almost done, I hope to have it up sometime this week.  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Nathan Asdourian</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-1615</link>
		<dc:creator>Nathan Asdourian</dc:creator>
		<pubDate>Mon, 16 Mar 2009 23:04:36 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-1615</guid>
		<description>Could you Please add an option to specify the database name as the database I&#039;m attempting to use this on must remain with the compatibility set to sql2000, I tried using the persons code that attempted this modification however when I have the proc print out the commands they don&#039;t come out correct therefor I don&#039;t believe I can trust what it&#039;s doing...</description>
		<content:encoded><![CDATA[<p>Could you Please add an option to specify the database name as the database I&#8217;m attempting to use this on must remain with the compatibility set to sql2000, I tried using the persons code that attempted this modification however when I have the proc print out the commands they don&#8217;t come out correct therefor I don&#8217;t believe I can trust what it&#8217;s doing&#8230;</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Perry Whittle</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-245</link>
		<dc:creator>Perry Whittle</dc:creator>
		<pubDate>Mon, 09 Feb 2009 23:09:38 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-245</guid>
		<description>Hi Michelle

change the recovery model to bulk logged first and there should be no transaction log issues as alter index is minimally logged in this mode.

regards

Perry</description>
		<content:encoded><![CDATA[<p>Hi Michelle</p>
<p>change the recovery model to bulk logged first and there should be no transaction log issues as alter index is minimally logged in this mode.</p>
<p>regards</p>
<p>Perry</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: SuperCoolMoss</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-222</link>
		<dc:creator>SuperCoolMoss</dc:creator>
		<pubDate>Thu, 05 Feb 2009 19:54:44 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-222</guid>
		<description>Hello Michelle,

I&#039;ve managed to get my changes to work with the help of colleague. I&#039;m a little inexperienced with T-SQL so sorry if I used any bad techniques. Here&#039;s the Enterprise version which is stored in a central database called DBAadmin and now takes a database name as a parameter.

IF EXISTS(SELECT OBJECT_ID FROM DBAAdmin.sys.tables
                WHERE [name] = N&#039;dba_indexDefragLog&#039;)
BEGIN
 
    DROP TABLE DBAAdmin.dbo.dba_indexDefragLog;
 
    PRINT &#039;dba_indexDefragLog table dropped!&#039;;
 
END
 
CREATE TABLE DBAadmin.dbo.dba_indexDefragLog
(
      databaseName      NVARCHAR(130)       NOT NULL
    , indexDefrag_id    INT IDENTITY(1,1)   NOT NULL
    , objectID          INT                 NOT NULL
    , objectName        NVARCHAR(130)       NOT NULL
    , indexID           INT                 NOT NULL
    , indexName         NVARCHAR(130)       NOT NULL
    , partitionNumber   SMALLINT            not null
    , fragmentation     FLOAT               NOT NULL
    , page_count        INT                 NOT NULL
    , dateTimeStart     DATETIME            NOT NULL
    , durationSeconds   INT                 NOT NULL
    CONSTRAINT PK_indexDefragLog
        PRIMARY KEY CLUSTERED (indexDefrag_id)
);
 
PRINT &#039;dba_indexDefragLog Table Created&#039;;

USE DBAAdmin
go
 
IF OBJECTPROPERTY(OBJECT_ID(&#039;dbo.dba_indexDefrag_sp&#039;),
        N&#039;IsProcedure&#039;) IS Null
BEGIN
    EXECUTE (&#039;Create Procedure dbo.dba_indexDefrag_sp
        As Print &#039;&#039;Hello World!&#039;&#039;&#039;);
    RAISERROR(&#039;Procedure dba_indexDefrag_sp created.&#039;
        , 10, 1);
END;
Go
 
SET ANSI_Nulls ON;
SET Ansi_Padding ON;
SET Ansi_Warnings ON;
SET ArithAbort ON;
SET Concat_Null_Yields_Null ON;
SET NOCOUNT ON;
SET Numeric_RoundAbort OFF;
SET Quoted_Identifier ON;
Go
 
ALTER PROCEDURE dbo.dba_indexDefrag_sp
 
    /* Declare Parameters */
      @minFragmentation     FLOAT           = 10.0
        /* in percent, will not defrag if fragmentation
           less than specified */
    , @rebuildThreshold     FLOAT           = 30.0
        /* in percent, greater than @rebuildThreshold
           will result in rebuild instead of reorg */
    , @onlineRebuild        BIT             = 1     
        /* 1 = online rebuild; 0 = offline rebuild */
    , @executeSQL           BIT             = 1
        /* 1 = execute; 0 = print command only */
    , @databaseName         VARCHAR(4000)   = &#039;DBAAdmin&#039;
        /* Specify database name */
    , @tableName            VARCHAR(4000)   = Null 
        /* Option to specify a table name */
    , @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)         = &#039;00:00:05&#039;
        /* time to wait between defrag commands */
AS
/********************************************************************
    Name:       dba_indexDefrag_sp
 
    Author:     Michelle F. Ufford, tampered with by SCM.
 
    Purpose:    Defrags all indexes for the specified database
 
    Notes:      This script was designed for SQL Server 2005
                Enterprise Edition.
 
    CAUTION: Monitor transaction log if executing for the first time!
 
      @minFragmentation     defaulted to 10%, will not defrag if
                            fragmentation if less than specified.
 
      @rebuildThreshold     defaulted to 30% as recommended by
                            Microsoft in BOL;
                            &gt; than 30% will result in rebuild instead
 
      @onlineRebuild        1 = online rebuild; 
                            0 = offline rebuild
 
      @executeSQL           1 = execute the SQL generated by this proc;
                            0 = print command only
 
      @databaseName         Specific database
 
      @tableName            Specify if you only want to defrag indexes
                            for a specific table
      
      @printCommands        1 = print commands to screen;
                            0 = do not print commands
 
      @printFragmentation   1 = print fragmentation to screen;
                            0 = do not print fragmentation
 
      @defragDelay          time to wait between defrag commands;
                            gives the server some time to catch up
 
    Called by:  SQL Agent Job or DBA
 
    Date        Initials  Description
    ----------------------------------------------------------------
    2008-10-27  MFU       Initial Release
    2008-11-17  MFU       Added page_count to log table
                          , added @printFragmentation option
    2009-02-05  SCM      Runs from central DB.      
********************************************************************
    Exec dbo.dba_indexDefrag_sp
          @databaseName = &#039;orders&#039;
          @executeSQL         = 1
        , @printCommands      = 1
        , @minFragmentation   = 0
        , @printFragmentation = 1;
********************************************************************/
 
SET NOCOUNT ON;
SET XACT_Abort ON;
 
BEGIN
 
    /* Declare our variables */
    DECLARE   @objectID         INT
            , @indexID          INT
            , @partitionCount   BIGINT
            , @schemaName       NVARCHAR(130)
            , @objectName       NVARCHAR(130)
            , @indexName        NVARCHAR(130)
            , @partitionNumber  SMALLINT
            , @partitions       SMALLINT
            , @fragmentation    FLOAT
            , @pageCount        INT
            , @sqlCommand       NVARCHAR(4000)
            , @rebuildCommand   NVARCHAR(200)
            , @dateTimeStart    DATETIME
            , @dateTimeEnd      DATETIME
            , @containsLOB      BIT;
 
    /* Just a little validation... */
    IF @minFragmentation Not Between 0.00 And 100.0
        SET @minFragmentation = 10.0;
 
    IF @rebuildThreshold Not Between 0.00 And 100.0
        SET @rebuildThreshold = 30.0;
 
    IF @defragDelay Not Like &#039;00:[0-5][0-9]:[0-5][0-9]&#039;
        SET @defragDelay = &#039;00:00:05&#039;;
 
    /* Determine which indexes to defrag using our
       user-defined parameters */
    SELECT
          OBJECT_ID AS objectID
        , index_id AS indexID
        , partition_number AS partitionNumber
        , avg_fragmentation_in_percent AS fragmentation
        , page_count 
        , 0 AS &#039;defragStatus&#039;
            /* 0 = unprocessed, 1 = processed */
    INTO ##indexDefragList
    FROM sys.dm_db_index_physical_stats
        (DB_ID(@databaseName), OBJECT_ID(@tableName), NULL , NULL, N&#039;Limited&#039;)
    WHERE avg_fragmentation_in_percent &gt; @minFragmentation
        And index_id &gt; 0
    OPTION (MaxDop 1);
 
    /* Create a clustered index to boost performance a little */
    CREATE CLUSTERED INDEX CIX_temp_indexDefragList
        ON ##indexDefragList(objectID, indexID, partitionNumber);
 
    /* Begin our loop for defragging */
    WHILE (SELECT COUNT(*) FROM ##indexDefragList
            WHERE defragStatus = 0) &gt; 0
    BEGIN
 
        /* Grab the most fragmented index first to defrag */
        SELECT TOP 1
              @objectID         = objectID
            , @fragmentation    = fragmentation
            , @indexID          = indexID
            , @partitionNumber  = partitionNumber
            , @pageCount        = page_count
        FROM ##indexDefragList
        WHERE defragStatus = 0
        ORDER BY fragmentation DESC;
 
        /* Look up index information */
	SET @sqlCommand = N&#039;SELECT QUOTENAME(o.name) AS objectName,QUOTENAME(s.name) AS schemaName into ##indexInfo1 FROM &#039; +
	    @databaseName + N&#039;.sys.objects AS o INNER Join &#039; + @databaseName + 
            N&#039;.sys.schemas AS s ON s.schema_id = o.schema_id WHERE o.object_id = &#039; + convert(varchar(256),@objectID) +
            N&#039;;&#039;;

        EXECUTE (@sqlCommand);

        SELECT @objectName = objectName,
               @schemaName = schemaName
        FROM ##indexInfo1;

--        SELECT @objectName = QUOTENAME(o.name)
--             , @schemaName = QUOTENAME(s.name)
--        FROM sys.objects AS o
--        INNER Join sys.schemas AS s
--            ON s.schema_id = o.schema_id
--        WHERE o.OBJECT_ID = @objectID;

	SET @sqlCommand = N&#039;SELECT QUOTENAME(name) AS indexName into ##indexInfo2 FROM &#039; +
	    @databaseName + N&#039;.sys.indexes WHERE object_id = &#039; + convert(varchar(256),@objectID) +
         N&#039; And index_id = &#039; + convert(varchar(256),@indexID) + N&#039; And type &gt; 0;&#039;;

        EXECUTE (@sqlCommand);

        SELECT @indexName = indexname from ##indexInfo2;
 
--        SELECT @indexName = QUOTENAME(name)
--        FROM sys.indexes
--        WHERE OBJECT_ID = @objectID
--            And index_id = @indexID
--            And type &gt; 0;
 
        /* Determine if the index is partitioned */

	SET @sqlCommand = N&#039;SELECT COUNT(*) AS partitionCount into ##indexInfo3 FROM &#039; + 
	    @databaseName + N&#039;.sys.partitions WHERE object_id = &#039; + convert(varchar(256),@objectID) +
            N&#039; And index_id = &#039; + convert(varchar(256),@indexID) + N&#039;;&#039;;

        EXECUTE (@sqlCommand);

        SELECT @partitionCount = partitionCount from ##indexInfo3;

--        SELECT @partitionCount = COUNT(*)
--        FROM sys.partitions
--        WHERE OBJECT_ID = @objectID
--        And index_id = @indexID;
 
        /* Look for LOBs */

       SET @sqlCommand = N&#039;SELECT TOP 1 column_id as containsLOB into ##indexInfo4 FROM &#039; +
           @databaseName + N&#039;.sys.columns with (NOLOCK) WHERE [object_id] = &#039; +
           convert(varchar(256),@objectID) + N&#039; And (system_type_id In (34, 35, 99) or max_length = -1);&#039;;

       EXECUTE (@sqlCommand);

       SELECT @containsLOB = containsLOB from ##indexInfo4;
 
--      SELECT TOP 1
--           @containsLOB = column_id
--       FROM sys.columns WITH (NOLOCK)
--        WHERE 
--            [OBJECT_ID] = @objectID
--            And (system_type_id In (34, 35, 99)
--            -- 34 = image, 35 = text, 99 = ntext
--                    Or max_length = -1);
--            -- varbinary(max), varchar(max), nvarchar(max), xml
 
        /* See if we should rebuild or reorganize; handle thusly */
        IF @fragmentation &lt; @rebuildThreshold And @partitionCount = @rebuildThreshold
            And IsNull(@containsLOB, 0) = 0
                -- Cannot rebuild if the table has one or more LOB
            And @partitionCount  1
            SET @sqlCommand = N&#039;Alter Index &#039; + @indexName + N&#039; On &#039;
                + @databaseName + N&#039;.&#039; + @schemaName + N&#039;.&#039; + @objectName + N&#039; ReOrganize&#039;
                + N&#039; Partition = &#039;
                + CAST(@partitionNumber AS NVARCHAR(10));
                -- no MaxDop needed, single threaded operation
 
        /* Are we executing the SQL?  If so, do it */
        IF @executeSQL = 1
        BEGIN
 
            /* Grab the time for logging purposes */
            SET @dateTimeStart  = GETDATE();
            EXECUTE (@sqlCommand);
            SET @dateTimeEnd  = GETDATE();
 
            /* Log our actions */
            INSERT INTO DBAadmin.dbo.dba_indexDefragLog
            (
                  databaseName
                , objectID
                , objectName
                , indexID
                , indexName
                , partitionNumber
                , fragmentation
                , page_count
                , dateTimeStart
                , durationSeconds
            )
            SELECT
                  @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&#039;Executed: &#039; + @sqlCommand;
        END
        ELSE
        /* Looks like we&#039;re not executing, just print
            the commands */
        BEGIN
            IF @printCommands = 1
                PRINT @sqlCommand;
        END
 
        /* Update our index defrag list when we&#039;ve
            finished with that index */
        UPDATE ##indexDefragList
        SET defragStatus = 1
        WHERE objectID         = @objectID
          And indexID          = @indexID
          And partitionNumber  = @partitionNumber;

    DROP TABLE ##indexInfo1;
    DROP TABLE ##indexInfo2;
    DROP TABLE ##indexInfo3;
    DROP TABLE ##indexInfo4;

    END
 
    /* Do we want to output our fragmentation results? */
      IF @printFragmentation = 1
         SET @sqlCommand = N&#039; SELECT &#039;&#039;&#039; + @databaseName + 
         N&#039;&#039;&#039;as&#039;&#039;DatabaseName&#039;&#039;, id1.objectID, o.name AS &#039;&#039;tableName&#039;&#039;, i.name AS &#039;&#039;indexName&#039;&#039;, id1.fragmentation, id1.page_count FROM ##indexDefragList as id1 Join &#039; + @databaseName + N&#039;.sys.objects AS o ON id1.objectID = o.object_id Join &#039;
         + @databaseName + N&#039;.sys.indexes AS i on id1.objectID = i.object_id and id1.indexID = i.index_id;&#039;
         EXECUTE (@sqlcommand);
 


--    IF @printFragmentation = 1
--        SELECT idl.objectID
--            , o.name AS &#039;tableName&#039;
--            , idl.indexID
--            , i.name AS &#039;indexName&#039;
--            , idl.fragmentation
--            , idl.page_count
--        FROM #indexDefragList AS idl
--        Join sys.objects AS o
--            ON idl.objectID = o.OBJECT_ID
--        Join sys.indexes AS i
--            ON idl.objectID = i.OBJECT_ID
--            And idl.indexID = i.index_id;
 
    /* When everything is done, make sure to get rid of
        our temp table */
    DROP TABLE ##indexDefragList;
 
    SET NOCOUNT OFF;
    RETURN 0
END
Go</description>
		<content:encoded><![CDATA[<p>Hello Michelle,</p>
<p>I&#8217;ve managed to get my changes to work with the help of colleague. I&#8217;m a little inexperienced with T-SQL so sorry if I used any bad techniques. Here&#8217;s the Enterprise version which is stored in a central database called DBAadmin and now takes a database name as a parameter.</p>
<p>IF EXISTS(SELECT OBJECT_ID FROM DBAAdmin.sys.tables<br />
                WHERE [name] = N&#8217;dba_indexDefragLog&#8217;)<br />
BEGIN</p>
<p>    DROP TABLE DBAAdmin.dbo.dba_indexDefragLog;</p>
<p>    PRINT &#8216;dba_indexDefragLog table dropped!&#8217;;</p>
<p>END</p>
<p>CREATE TABLE DBAadmin.dbo.dba_indexDefragLog<br />
(<br />
      databaseName      NVARCHAR(130)       NOT NULL<br />
    , indexDefrag_id    INT IDENTITY(1,1)   NOT NULL<br />
    , objectID          INT                 NOT NULL<br />
    , objectName        NVARCHAR(130)       NOT NULL<br />
    , indexID           INT                 NOT NULL<br />
    , indexName         NVARCHAR(130)       NOT NULL<br />
    , partitionNumber   SMALLINT            not null<br />
    , fragmentation     FLOAT               NOT NULL<br />
    , page_count        INT                 NOT NULL<br />
    , dateTimeStart     DATETIME            NOT NULL<br />
    , durationSeconds   INT                 NOT NULL<br />
    CONSTRAINT PK_indexDefragLog<br />
        PRIMARY KEY CLUSTERED (indexDefrag_id)<br />
);</p>
<p>PRINT &#8216;dba_indexDefragLog Table Created&#8217;;</p>
<p>USE DBAAdmin<br />
go</p>
<p>IF OBJECTPROPERTY(OBJECT_ID(&#8216;dbo.dba_indexDefrag_sp&#8217;),<br />
        N&#8217;IsProcedure&#8217;) IS Null<br />
BEGIN<br />
    EXECUTE (&#8216;Create Procedure dbo.dba_indexDefrag_sp<br />
        As Print &#8221;Hello World!&#8221;&#8217;);<br />
    RAISERROR(&#8216;Procedure dba_indexDefrag_sp created.&#8217;<br />
        , 10, 1);<br />
END;<br />
Go</p>
<p>SET ANSI_Nulls ON;<br />
SET Ansi_Padding ON;<br />
SET Ansi_Warnings ON;<br />
SET ArithAbort ON;<br />
SET Concat_Null_Yields_Null ON;<br />
SET NOCOUNT ON;<br />
SET Numeric_RoundAbort OFF;<br />
SET Quoted_Identifier ON;<br />
Go</p>
<p>ALTER PROCEDURE dbo.dba_indexDefrag_sp</p>
<p>    /* Declare Parameters */<br />
      @minFragmentation     FLOAT           = 10.0<br />
        /* in percent, will not defrag if fragmentation<br />
           less than specified */<br />
    , @rebuildThreshold     FLOAT           = 30.0<br />
        /* in percent, greater than @rebuildThreshold<br />
           will result in rebuild instead of reorg */<br />
    , @onlineRebuild        BIT             = 1<br />
        /* 1 = online rebuild; 0 = offline rebuild */<br />
    , @executeSQL           BIT             = 1<br />
        /* 1 = execute; 0 = print command only */<br />
    , @databaseName         VARCHAR(4000)   = &#8216;DBAAdmin&#8217;<br />
        /* Specify database name */<br />
    , @tableName            VARCHAR(4000)   = Null<br />
        /* Option to specify a table name */<br />
    , @printCommands        BIT             = 0<br />
        /* 1 = print commands; 0 = do not print commands */<br />
    , @printFragmentation   BIT             = 0<br />
        /* 1 = print fragmentation prior to defrag;<br />
           0 = do not print */<br />
    , @defragDelay          CHAR(8)         = &#8217;00:00:05&#8242;<br />
        /* time to wait between defrag commands */<br />
AS<br />
/********************************************************************<br />
    Name:       dba_indexDefrag_sp</p>
<p>    Author:     Michelle F. Ufford, tampered with by SCM.</p>
<p>    Purpose:    Defrags all indexes for the specified database</p>
<p>    Notes:      This script was designed for SQL Server 2005<br />
                Enterprise Edition.</p>
<p>    CAUTION: Monitor transaction log if executing for the first time!</p>
<p>      @minFragmentation     defaulted to 10%, will not defrag if<br />
                            fragmentation if less than specified.</p>
<p>      @rebuildThreshold     defaulted to 30% as recommended by<br />
                            Microsoft in BOL;<br />
                            &gt; than 30% will result in rebuild instead</p>
<p>      @onlineRebuild        1 = online rebuild;<br />
                            0 = offline rebuild</p>
<p>      @executeSQL           1 = execute the SQL generated by this proc;<br />
                            0 = print command only</p>
<p>      @databaseName         Specific database</p>
<p>      @tableName            Specify if you only want to defrag indexes<br />
                            for a specific table</p>
<p>      @printCommands        1 = print commands to screen;<br />
                            0 = do not print commands</p>
<p>      @printFragmentation   1 = print fragmentation to screen;<br />
                            0 = do not print fragmentation</p>
<p>      @defragDelay          time to wait between defrag commands;<br />
                            gives the server some time to catch up</p>
<p>    Called by:  SQL Agent Job or DBA</p>
<p>    Date        Initials  Description<br />
    &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
    2008-10-27  MFU       Initial Release<br />
    2008-11-17  MFU       Added page_count to log table<br />
                          , added @printFragmentation option<br />
    2009-02-05  SCM      Runs from central DB.<br />
********************************************************************<br />
    Exec dbo.dba_indexDefrag_sp<br />
          @databaseName = &#8216;orders&#8217;<br />
          @executeSQL         = 1<br />
        , @printCommands      = 1<br />
        , @minFragmentation   = 0<br />
        , @printFragmentation = 1;<br />
********************************************************************/</p>
<p>SET NOCOUNT ON;<br />
SET XACT_Abort ON;</p>
<p>BEGIN</p>
<p>    /* Declare our variables */<br />
    DECLARE   @objectID         INT<br />
            , @indexID          INT<br />
            , @partitionCount   BIGINT<br />
            , @schemaName       NVARCHAR(130)<br />
            , @objectName       NVARCHAR(130)<br />
            , @indexName        NVARCHAR(130)<br />
            , @partitionNumber  SMALLINT<br />
            , @partitions       SMALLINT<br />
            , @fragmentation    FLOAT<br />
            , @pageCount        INT<br />
            , @sqlCommand       NVARCHAR(4000)<br />
            , @rebuildCommand   NVARCHAR(200)<br />
            , @dateTimeStart    DATETIME<br />
            , @dateTimeEnd      DATETIME<br />
            , @containsLOB      BIT;</p>
<p>    /* Just a little validation&#8230; */<br />
    IF @minFragmentation Not Between 0.00 And 100.0<br />
        SET @minFragmentation = 10.0;</p>
<p>    IF @rebuildThreshold Not Between 0.00 And 100.0<br />
        SET @rebuildThreshold = 30.0;</p>
<p>    IF @defragDelay Not Like &#8217;00:[0-5][0-9]:[0-5][0-9]&#8216;<br />
        SET @defragDelay = &#8217;00:00:05&#8242;;</p>
<p>    /* Determine which indexes to defrag using our<br />
       user-defined parameters */<br />
    SELECT<br />
          OBJECT_ID AS objectID<br />
        , index_id AS indexID<br />
        , partition_number AS partitionNumber<br />
        , avg_fragmentation_in_percent AS fragmentation<br />
        , page_count<br />
        , 0 AS &#8216;defragStatus&#8217;<br />
            /* 0 = unprocessed, 1 = processed */<br />
    INTO ##indexDefragList<br />
    FROM sys.dm_db_index_physical_stats<br />
        (DB_ID(@databaseName), OBJECT_ID(@tableName), NULL , NULL, N&#8217;Limited&#8217;)<br />
    WHERE avg_fragmentation_in_percent &gt; @minFragmentation<br />
        And index_id &gt; 0<br />
    OPTION (MaxDop 1);</p>
<p>    /* Create a clustered index to boost performance a little */<br />
    CREATE CLUSTERED INDEX CIX_temp_indexDefragList<br />
        ON ##indexDefragList(objectID, indexID, partitionNumber);</p>
<p>    /* Begin our loop for defragging */<br />
    WHILE (SELECT COUNT(*) FROM ##indexDefragList<br />
            WHERE defragStatus = 0) &gt; 0<br />
    BEGIN</p>
<p>        /* Grab the most fragmented index first to defrag */<br />
        SELECT TOP 1<br />
              @objectID         = objectID<br />
            , @fragmentation    = fragmentation<br />
            , @indexID          = indexID<br />
            , @partitionNumber  = partitionNumber<br />
            , @pageCount        = page_count<br />
        FROM ##indexDefragList<br />
        WHERE defragStatus = 0<br />
        ORDER BY fragmentation DESC;</p>
<p>        /* Look up index information */<br />
	SET @sqlCommand = N&#8217;SELECT QUOTENAME(o.name) AS objectName,QUOTENAME(s.name) AS schemaName into ##indexInfo1 FROM &#8216; +<br />
	    @databaseName + N&#8217;.sys.objects AS o INNER Join &#8216; + @databaseName +<br />
            N&#8217;.sys.schemas AS s ON s.schema_id = o.schema_id WHERE o.object_id = &#8216; + convert(varchar(256),@objectID) +<br />
            N&#8217;;';</p>
<p>        EXECUTE (@sqlCommand);</p>
<p>        SELECT @objectName = objectName,<br />
               @schemaName = schemaName<br />
        FROM ##indexInfo1;</p>
<p>&#8211;        SELECT @objectName = QUOTENAME(o.name)<br />
&#8211;             , @schemaName = QUOTENAME(s.name)<br />
&#8211;        FROM sys.objects AS o<br />
&#8211;        INNER Join sys.schemas AS s<br />
&#8211;            ON s.schema_id = o.schema_id<br />
&#8211;        WHERE o.OBJECT_ID = @objectID;</p>
<p>	SET @sqlCommand = N&#8217;SELECT QUOTENAME(name) AS indexName into ##indexInfo2 FROM &#8216; +<br />
	    @databaseName + N&#8217;.sys.indexes WHERE object_id = &#8216; + convert(varchar(256),@objectID) +<br />
         N&#8217; And index_id = &#8216; + convert(varchar(256),@indexID) + N&#8217; And type &gt; 0;&#8217;;</p>
<p>        EXECUTE (@sqlCommand);</p>
<p>        SELECT @indexName = indexname from ##indexInfo2;</p>
<p>&#8211;        SELECT @indexName = QUOTENAME(name)<br />
&#8211;        FROM sys.indexes<br />
&#8211;        WHERE OBJECT_ID = @objectID<br />
&#8211;            And index_id = @indexID<br />
&#8211;            And type &gt; 0;</p>
<p>        /* Determine if the index is partitioned */</p>
<p>	SET @sqlCommand = N&#8217;SELECT COUNT(*) AS partitionCount into ##indexInfo3 FROM &#8216; +<br />
	    @databaseName + N&#8217;.sys.partitions WHERE object_id = &#8216; + convert(varchar(256),@objectID) +<br />
            N&#8217; And index_id = &#8216; + convert(varchar(256),@indexID) + N&#8217;;';</p>
<p>        EXECUTE (@sqlCommand);</p>
<p>        SELECT @partitionCount = partitionCount from ##indexInfo3;</p>
<p>&#8211;        SELECT @partitionCount = COUNT(*)<br />
&#8211;        FROM sys.partitions<br />
&#8211;        WHERE OBJECT_ID = @objectID<br />
&#8211;        And index_id = @indexID;</p>
<p>        /* Look for LOBs */</p>
<p>       SET @sqlCommand = N&#8217;SELECT TOP 1 column_id as containsLOB into ##indexInfo4 FROM &#8216; +<br />
           @databaseName + N&#8217;.sys.columns with (NOLOCK) WHERE [object_id] = &#8216; +<br />
           convert(varchar(256),@objectID) + N&#8217; And (system_type_id In (34, 35, 99) or max_length = -1);&#8217;;</p>
<p>       EXECUTE (@sqlCommand);</p>
<p>       SELECT @containsLOB = containsLOB from ##indexInfo4;</p>
<p>&#8211;      SELECT TOP 1<br />
&#8211;           @containsLOB = column_id<br />
&#8211;       FROM sys.columns WITH (NOLOCK)<br />
&#8211;        WHERE<br />
&#8211;            [OBJECT_ID] = @objectID<br />
&#8211;            And (system_type_id In (34, 35, 99)<br />
&#8211;            &#8212; 34 = image, 35 = text, 99 = ntext<br />
&#8211;                    Or max_length = -1);<br />
&#8211;            &#8212; varbinary(max), varchar(max), nvarchar(max), xml</p>
<p>        /* See if we should rebuild or reorganize; handle thusly */<br />
        IF @fragmentation &lt; @rebuildThreshold And @partitionCount = @rebuildThreshold<br />
            And IsNull(@containsLOB, 0) = 0<br />
                &#8212; Cannot rebuild if the table has one or more LOB<br />
            And @partitionCount  1<br />
            SET @sqlCommand = N&#8217;Alter Index &#8216; + @indexName + N&#8217; On &#8216;<br />
                + @databaseName + N&#8217;.&#8217; + @schemaName + N&#8217;.&#8217; + @objectName + N&#8217; ReOrganize&#8217;<br />
                + N&#8217; Partition = &#8216;<br />
                + CAST(@partitionNumber AS NVARCHAR(10));<br />
                &#8212; no MaxDop needed, single threaded operation</p>
<p>        /* Are we executing the SQL?  If so, do it */<br />
        IF @executeSQL = 1<br />
        BEGIN</p>
<p>            /* Grab the time for logging purposes */<br />
            SET @dateTimeStart  = GETDATE();<br />
            EXECUTE (@sqlCommand);<br />
            SET @dateTimeEnd  = GETDATE();</p>
<p>            /* Log our actions */<br />
            INSERT INTO DBAadmin.dbo.dba_indexDefragLog<br />
            (<br />
                  databaseName<br />
                , objectID<br />
                , objectName<br />
                , indexID<br />
                , indexName<br />
                , partitionNumber<br />
                , fragmentation<br />
                , page_count<br />
                , dateTimeStart<br />
                , durationSeconds<br />
            )<br />
            SELECT<br />
                  @databaseName<br />
                , @objectID<br />
                , @objectName<br />
                , @indexID<br />
                , @indexName<br />
                , @partitionNumber<br />
                , @fragmentation<br />
                , @pageCount<br />
                , @dateTimeStart<br />
                , DATEDIFF(SECOND, @dateTimeStart, @dateTimeEnd);</p>
<p>            /* Just a little breather for the server */<br />
            WAITFOR Delay @defragDelay;</p>
<p>            /* Print if specified to do so */<br />
            IF @printCommands = 1<br />
                PRINT N&#8217;Executed: &#8216; + @sqlCommand;<br />
        END<br />
        ELSE<br />
        /* Looks like we&#8217;re not executing, just print<br />
            the commands */<br />
        BEGIN<br />
            IF @printCommands = 1<br />
                PRINT @sqlCommand;<br />
        END</p>
<p>        /* Update our index defrag list when we&#8217;ve<br />
            finished with that index */<br />
        UPDATE ##indexDefragList<br />
        SET defragStatus = 1<br />
        WHERE objectID         = @objectID<br />
          And indexID          = @indexID<br />
          And partitionNumber  = @partitionNumber;</p>
<p>    DROP TABLE ##indexInfo1;<br />
    DROP TABLE ##indexInfo2;<br />
    DROP TABLE ##indexInfo3;<br />
    DROP TABLE ##indexInfo4;</p>
<p>    END</p>
<p>    /* Do we want to output our fragmentation results? */<br />
      IF @printFragmentation = 1<br />
         SET @sqlCommand = N&#8217; SELECT &#8221;&#8217; + @databaseName +<br />
         N&#8221;&#8217;as&#8221;DatabaseName&#8221;, id1.objectID, o.name AS &#8221;tableName&#8221;, i.name AS &#8221;indexName&#8221;, id1.fragmentation, id1.page_count FROM ##indexDefragList as id1 Join &#8216; + @databaseName + N&#8217;.sys.objects AS o ON id1.objectID = o.object_id Join &#8216;<br />
         + @databaseName + N&#8217;.sys.indexes AS i on id1.objectID = i.object_id and id1.indexID = i.index_id;&#8217;<br />
         EXECUTE (@sqlcommand);</p>
<p>&#8211;    IF @printFragmentation = 1<br />
&#8211;        SELECT idl.objectID<br />
&#8211;            , o.name AS &#8216;tableName&#8217;<br />
&#8211;            , idl.indexID<br />
&#8211;            , i.name AS &#8216;indexName&#8217;<br />
&#8211;            , idl.fragmentation<br />
&#8211;            , idl.page_count<br />
&#8211;        FROM #indexDefragList AS idl<br />
&#8211;        Join sys.objects AS o<br />
&#8211;            ON idl.objectID = o.OBJECT_ID<br />
&#8211;        Join sys.indexes AS i<br />
&#8211;            ON idl.objectID = i.OBJECT_ID<br />
&#8211;            And idl.indexID = i.index_id;</p>
<p>    /* When everything is done, make sure to get rid of<br />
        our temp table */<br />
    DROP TABLE ##indexDefragList;</p>
<p>    SET NOCOUNT OFF;<br />
    RETURN 0<br />
END<br />
Go</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-206</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Mon, 02 Feb 2009 23:12:40 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-206</guid>
		<description>Hi SCM!  

To be honest, I just use a single SQL Agent Job, then add job steps for each of my databases.  I know someone modified the script to do exactly what you&#039;re asking for, so I&#039;ll see if they&#039;re interested in sharing their work.  :)</description>
		<content:encoded><![CDATA[<p>Hi SCM!  </p>
<p>To be honest, I just use a single SQL Agent Job, then add job steps for each of my databases.  I know someone modified the script to do exactly what you&#8217;re asking for, so I&#8217;ll see if they&#8217;re interested in sharing their work.  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: SuperCoolMoss</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-205</link>
		<dc:creator>SuperCoolMoss</dc:creator>
		<pubDate>Mon, 02 Feb 2009 21:25:59 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-205</guid>
		<description>Hello,

I&#039;m trying to modify this script to run against all databases within an instance of SQL 2005 (consolidated sever), but I&#039;m struggling. 

I could install this into each database, but I&#039;d prefer to install into just one controlling database and have it execute against all databases.

Any pointers as to the best way to archive this? 

Regards,

SCM</description>
		<content:encoded><![CDATA[<p>Hello,</p>
<p>I&#8217;m trying to modify this script to run against all databases within an instance of SQL 2005 (consolidated sever), but I&#8217;m struggling. </p>
<p>I could install this into each database, but I&#8217;d prefer to install into just one controlling database and have it execute against all databases.</p>
<p>Any pointers as to the best way to archive this? </p>
<p>Regards,</p>
<p>SCM</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Marcel Rokers</title>
		<link>http://sqlfool.com/2008/11/updated-index-defrag-script-2005-2008/comment-page-1/#comment-112</link>
		<dc:creator>Marcel Rokers</dc:creator>
		<pubDate>Mon, 29 Dec 2008 13:42:27 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=183#comment-112</guid>
		<description>That&#039;s why I would like a downloadable version of the script.</description>
		<content:encoded><![CDATA[<p>That&#8217;s why I would like a downloadable version of the script.</p>
]]></content:encoded>
	</item>
</channel>
</rss>

