<?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: Index Defrag Script, v3.0</title>
	<atom:link href="http://sqlfool.com/2009/06/index-defrag-script-v30/feed/" rel="self" type="application/rss+xml" />
	<link>http://sqlfool.com/2009/06/index-defrag-script-v30/</link>
	<description>Adventures in SQL Tuning - a blog for the rest of us</description>
	<lastBuildDate>Thu, 04 Feb 2010 08:21:02 -0700</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: Dale Langham</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5055</link>
		<dc:creator>Dale Langham</dc:creator>
		<pubDate>Tue, 02 Feb 2010 16:22:15 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5055</guid>
		<description>After running the script, you should run the following command to analyze and re-index the entire database:
EXEC dbo.p_maint_ExecuteMaintTasks @PeriodLength = 1
By passing @PeriodLength = 1, the procedure will perform all maintenance tasks in a single execution rather than dividing them up across multiple executions.
To set up recurring maintenance, you need a SQL Agent job that runs p_maint_ExecuteMaintTasks on a regular basis (if using the default settings, daily).  No parameters are necessary to run this stored procedure with default settings.  Using default settings, the procedure will divide all index maintenance tasks over a 7-day period with a near equal as possible load each day.
The stored procedure breaks the maintenance into two main steps: scheduling and execution.  The scheduling phase runs DBCC SHOWCONTIG WITH FAST to determine which indexes need to be defragmented and approximately how much work this will be.  It applies several layers of logic including a fragmentation threshold (default 10% logical fragmentation) and eliminating duplicate defrag operations due to non-clustered/clustered indexes on the same table.  For indexes where defragmentation isn’t needed, it schedules an update statistics operation.
The scheduling phase also estimates the approximate relative cost of each operation and attempts to assign each operation to a specific interval within the maintenance period.  By default, the maintenance period is 7 days long, and each period is one day.  The scheduling phase runs once per period while the execution phase runs once per interval.  (So by default, scheduling occurs weekly while maintenance execution occurs daily.)  The results of the scheduling phase are stored in the DBMaint_Task table.</description>
		<content:encoded><![CDATA[<p>After running the script, you should run the following command to analyze and re-index the entire database:<br />
EXEC dbo.p_maint_ExecuteMaintTasks @PeriodLength = 1<br />
By passing @PeriodLength = 1, the procedure will perform all maintenance tasks in a single execution rather than dividing them up across multiple executions.<br />
To set up recurring maintenance, you need a SQL Agent job that runs p_maint_ExecuteMaintTasks on a regular basis (if using the default settings, daily).  No parameters are necessary to run this stored procedure with default settings.  Using default settings, the procedure will divide all index maintenance tasks over a 7-day period with a near equal as possible load each day.<br />
The stored procedure breaks the maintenance into two main steps: scheduling and execution.  The scheduling phase runs DBCC SHOWCONTIG WITH FAST to determine which indexes need to be defragmented and approximately how much work this will be.  It applies several layers of logic including a fragmentation threshold (default 10% logical fragmentation) and eliminating duplicate defrag operations due to non-clustered/clustered indexes on the same table.  For indexes where defragmentation isn’t needed, it schedules an update statistics operation.<br />
The scheduling phase also estimates the approximate relative cost of each operation and attempts to assign each operation to a specific interval within the maintenance period.  By default, the maintenance period is 7 days long, and each period is one day.  The scheduling phase runs once per period while the execution phase runs once per interval.  (So by default, scheduling occurs weekly while maintenance execution occurs daily.)  The results of the scheduling phase are stored in the DBMaint_Task table.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Dale Langham</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5054</link>
		<dc:creator>Dale Langham</dc:creator>
		<pubDate>Tue, 02 Feb 2010 16:20:11 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5054</guid>
		<description>Hi,
Not sure where I had this script from, but I have been using it for ages now, basically it defrags indexes over a period of 7 days to spread the load, but for some reason it doesn&#039;t like multiple schemas, as it adds dbo to all tables found etc... any ideas to make this work for all schemas would be great:

IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(&#039;dbo.DBMaint_Task&#039;) AND xtype = &#039;U&#039;)
BEGIN
	DROP TABLE dbo.DBMaint_Task
END
GO

CREATE TABLE dbo.DBMaint_Task(
	MaintTaskId		int		NOT NULL	IDENTITY(1, 1),
	Interval		int		NOT NULL,
	Command			nvarchar(4000)	NOT NULL,
	ItemWork		numeric(10,2)	NOT NULL,
	CompletedDatetime	datetime	NULL
	CONSTRAINT PK_DBMaint_Task PRIMARY KEY CLUSTERED(MaintTaskID)
)
GO

IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(&#039;dbo.p_maint_ScheduleMaintTasks&#039;) AND xtype = &#039;P&#039;)
BEGIN
	DROP PROCEDURE dbo.p_maint_ScheduleMaintTasks
END
GO

CREATE PROCEDURE dbo.p_maint_ScheduleMaintTasks
	@PeriodLength		int,		-- Number of intervals in a period
	@IndexRebuildThreshold	int	= 10	-- Maximum LogicalFragmentation value allowed before an index is rebuilt
AS

DECLARE @WorkPerIntervalGoal 	numeric(10,2)
DECLARE @CurrentInterval	int
DECLARE @RowsUpdated		int
DECLARE @MainTaskId		int

SET NOCOUNT ON

IF @PeriodLength = @IndexRebuildThreshold
	AND
	ObjectId  OBJECT_ID(&#039;dbo.DBMaint_Task&#039;)


-- If we rebuild a clustered index, we don&#039;t need to rebuild 
-- any nonclustered indexes on the same table
DELETE FROM
	rc1
FROM
	#ReindexCandidate rc1
INNER JOIN
	#ReindexCandidate rc2
	ON(
		rc1.ObjectId = rc2.ObjectId
	)
WHERE
	rc2.IndexID = 1 -- IndexID = 1 means the clustered index
	AND
	rc1.IndexID  1


TRUNCATE TABLE dbo.DBMaint_Task

INSERT INTO dbo.DBMaint_Task(
	Interval,
	Command,
	ItemWork)
SELECT
	-1 AS Interval,
	N&#039;DBCC DBREINDEX(&#039;&#039;&#039; + USER_NAME(OBJECTPROPERTY(rc1.ObjectId, &#039;OwnerId&#039;)) + N&#039;.&#039; + rc1.ObjectName + N&#039;&#039;&#039;&#039; + 
		CASE IndexId WHEN 1 THEN N&#039;&#039; ELSE N&#039;, &#039;&#039;&#039; + IndexName + N&#039;&#039;&#039;&#039; END + N&#039;)&#039; AS Command,
	(SELECT SUM(dpages) FROM dbo.sysindexes si1 WHERE id = rc1.ObjectId) AS ItemWork
FROM
	#ReindexCandidate rc1

-- Find all tables that we&#039;re not doing a clustered index rebuild on
INSERT INTO dbo.DBMaint_Task(
	Interval,
	Command,
	ItemWork)
SELECT
	-1 AS Interval,
	N&#039;UPDATE STATISTICS [&#039; + USER_NAME(uid) + N&#039;].[&#039; + so1.name + N&#039;] WITH FULLSCAN&#039; AS Command,
	(SELECT SUM(dpages) FROM dbo.sysindexes si1 WHERE id = so1.id) * 0.40 AS ItemWork
FROM
	dbo.sysobjects so1
LEFT OUTER JOIN 
	#ReindexCandidate rc1
	ON 
		(
			rc1.ObjectId = so1.id
			AND
			rc1.IndexId = 1
		)
WHERE
	so1.xtype = &#039;U&#039;
	AND
	rc1.ObjectId IS NULL
	AND
	(SELECT SUM(dpages) FROM dbo.sysindexes si1 WHERE id = so1.id)  0
	AND
	so1.id  OBJECT_ID(&#039;dbo.DBMaint_Task&#039;)

DELETE FROM
	dbo.DBMaint_Task
WHERE
	ItemWork = 0

-- Break all ties by ItemWork
-- This algorithm is arbitrary, but the amount of estimated work it adds is trival
SET @RowsUpdated = 1
WHILE @RowsUpdated  0
BEGIN
	UPDATE
		mt1
	SET
		ItemWork = ItemWork + 0.01
	FROM
		dbo.DBMaint_Task mt1
	INNER JOIN
		(
			SELECT
				MAX(MaintTaskId) AS MaintTaskId
			FROM
				dbo.DBMaint_Task
			GROUP BY
				ItemWork
			HAVING
				COUNT(*) &gt; 1
		) mt2
	ON
		(
			mt1.MaintTaskId = mt2.MaintTaskId
		)
	
	SET @RowsUpdated = @@ROWCOUNT
END		


SET @CurrentInterval = 1
WHILE @CurrentInterval = mt1.ItemWork 
				AND 
				mt2.Interval = -1
		) &lt;= @WorkPerIntervalGoal	
	
	SET @RowsUpdated = @@ROWCOUNT

	IF @RowsUpdated = 0
	BEGIN
		UPDATE
			mt1
		SET
			Interval = @CurrentInterval
		FROM
			dbo.DBMaint_Task mt1
		WHERE
		mt1.ItemWork = (
			SELECT 
				MAX(mt2.ItemWork) 
			FROM 
				dbo.DBMaint_Task mt2
			WHERE 
				mt2.Interval = -1
		)
	END

	SET @CurrentInterval = @CurrentInterval + 1
END

SET NOCOUNT OFF

GO


IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(&#039;dbo.p_maint_ExecuteMaintTasks&#039;) AND xtype = &#039;P&#039;)
BEGIN
	DROP PROCEDURE dbo.p_maint_ExecuteMaintTasks
END
GO

CREATE PROCEDURE dbo.p_maint_ExecuteMaintTasks
	@PeriodLength 			int = 7,	-- Number of intervals in a period
	@IndexRebuildThreshold		int = 10,	-- Maximum LogicalFragmentation value allowed before an index is rebuilt
	@ForceInterval			int = NULL,	-- Manually set the current interval rather than calculating it from the date
	@ForceRebuildTaskList 		int = 0,	-- If non-zero, force a rebuild of the task list
	@RebuildTaskListInterval	int = 1		-- The interval in which to automatically rebuild the task list
AS

DECLARE @CurrentInterval	 	int
DECLARE @TaskCount			int
DECLARE @Command			nvarchar(4000)
DECLARE @MaintTaskId			int

SET NOCOUNT ON

IF @PeriodLength &lt; 1
BEGIN
	RAISERROR(N&#039;@PeriodLength must be greater than zero.&#039;, 16, 1)
	RETURN
END

IF @ForceInterval IS NOT NULL
BEGIN
	IF @ForceInterval  @PeriodLength
	BEGIN
		RAISERROR(N&#039;If not null, @ForceInterval must be less than or equal to @PeriodLength.&#039;, 16, 1)
		RETURN
	END
END

IF @RebuildTaskListInterval &gt; @PeriodLength
BEGIN
	RAISERROR(N&#039;@RebuildTaskListInterval must be less than or equal to @PeriodLength.&#039;, 16, 1)
	RETURN
END

IF NOT @IndexRebuildThreshold BETWEEN 0 AND 100
BEGIN
	RAISERROR(N&#039;@IndexRebuildThreshold must be between 0 and 100.&#039;, 16, 1)
	RETURN
END

SELECT
	@TaskCount = COUNT(*)
FROM
	dbo.DBMaint_Task
WHERE
	CompletedDatetime IS NULL

IF @ForceInterval IS NULL
BEGIN
	SELECT 
		@CurrentInterval = ((YEAR(GETDATE() - 59) * 365 + DATEPART(dy, GETDATE() - 59)) % @PeriodLength) + 1
END
ELSE
BEGIN
	SELECT
		@CurrentInterval = @ForceInterval
END

IF @TaskCount = 0 OR @ForceRebuildTaskList  0 OR @CurrentInterval = @RebuildTaskListInterval
BEGIN
	EXEC dbo.p_maint_ScheduleMaintTasks 
		@PeriodLength = @PeriodLength,
		@IndexRebuildThreshold = @IndexRebuildThreshold
END

DECLARE csr_Task CURSOR FAST_FORWARD FOR
SELECT
	MaintTaskId,
	Command
FROM
	dbo.DBMaint_Task
WHERE
	Interval = @CurrentInterval
	AND
	CompletedDatetime IS NULL

OPEN csr_Task

FETCH NEXT FROM csr_Task INTO @MaintTaskId, @Command
WHILE @@FETCH_STATUS = 0
BEGIN
	PRINT CONVERT(nvarchar(30), GETDATE(), 121) + N&#039;: Executing &quot;&#039; + @Command + N&#039;&quot;&#039;
	EXEC(@Command)
	PRINT &#039;&#039;

	UPDATE
		dbo.DBMaint_Task
	SET
		CompletedDatetime = GETDATE()
	WHERE
		MaintTaskId = @MaintTaskId

	FETCH NEXT FROM csr_Task INTO @MaintTaskId, @Command
END

CLOSE csr_Task
DEALLOCATE csr_Task

SET NOCOUNT OFF
GO</description>
		<content:encoded><![CDATA[<p>Hi,<br />
Not sure where I had this script from, but I have been using it for ages now, basically it defrags indexes over a period of 7 days to spread the load, but for some reason it doesn&#8217;t like multiple schemas, as it adds dbo to all tables found etc&#8230; any ideas to make this work for all schemas would be great:</p>
<p>IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(&#8216;dbo.DBMaint_Task&#8217;) AND xtype = &#8216;U&#8217;)<br />
BEGIN<br />
	DROP TABLE dbo.DBMaint_Task<br />
END<br />
GO</p>
<p>CREATE TABLE dbo.DBMaint_Task(<br />
	MaintTaskId		int		NOT NULL	IDENTITY(1, 1),<br />
	Interval		int		NOT NULL,<br />
	Command			nvarchar(4000)	NOT NULL,<br />
	ItemWork		numeric(10,2)	NOT NULL,<br />
	CompletedDatetime	datetime	NULL<br />
	CONSTRAINT PK_DBMaint_Task PRIMARY KEY CLUSTERED(MaintTaskID)<br />
)<br />
GO</p>
<p>IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(&#8216;dbo.p_maint_ScheduleMaintTasks&#8217;) AND xtype = &#8216;P&#8217;)<br />
BEGIN<br />
	DROP PROCEDURE dbo.p_maint_ScheduleMaintTasks<br />
END<br />
GO</p>
<p>CREATE PROCEDURE dbo.p_maint_ScheduleMaintTasks<br />
	@PeriodLength		int,		&#8211; Number of intervals in a period<br />
	@IndexRebuildThreshold	int	= 10	&#8211; Maximum LogicalFragmentation value allowed before an index is rebuilt<br />
AS</p>
<p>DECLARE @WorkPerIntervalGoal 	numeric(10,2)<br />
DECLARE @CurrentInterval	int<br />
DECLARE @RowsUpdated		int<br />
DECLARE @MainTaskId		int</p>
<p>SET NOCOUNT ON</p>
<p>IF @PeriodLength = @IndexRebuildThreshold<br />
	AND<br />
	ObjectId  OBJECT_ID(&#8216;dbo.DBMaint_Task&#8217;)</p>
<p>&#8211; If we rebuild a clustered index, we don&#8217;t need to rebuild<br />
&#8211; any nonclustered indexes on the same table<br />
DELETE FROM<br />
	rc1<br />
FROM<br />
	#ReindexCandidate rc1<br />
INNER JOIN<br />
	#ReindexCandidate rc2<br />
	ON(<br />
		rc1.ObjectId = rc2.ObjectId<br />
	)<br />
WHERE<br />
	rc2.IndexID = 1 &#8212; IndexID = 1 means the clustered index<br />
	AND<br />
	rc1.IndexID  1</p>
<p>TRUNCATE TABLE dbo.DBMaint_Task</p>
<p>INSERT INTO dbo.DBMaint_Task(<br />
	Interval,<br />
	Command,<br />
	ItemWork)<br />
SELECT<br />
	-1 AS Interval,<br />
	N&#8217;DBCC DBREINDEX(&#8221;&#8217; + USER_NAME(OBJECTPROPERTY(rc1.ObjectId, &#8216;OwnerId&#8217;)) + N&#8217;.&#8217; + rc1.ObjectName + N&#8221;&#8221; +<br />
		CASE IndexId WHEN 1 THEN N&#8221; ELSE N&#8217;, &#8221;&#8217; + IndexName + N&#8221;&#8221; END + N&#8217;)&#8217; AS Command,<br />
	(SELECT SUM(dpages) FROM dbo.sysindexes si1 WHERE id = rc1.ObjectId) AS ItemWork<br />
FROM<br />
	#ReindexCandidate rc1</p>
<p>&#8211; Find all tables that we&#8217;re not doing a clustered index rebuild on<br />
INSERT INTO dbo.DBMaint_Task(<br />
	Interval,<br />
	Command,<br />
	ItemWork)<br />
SELECT<br />
	-1 AS Interval,<br />
	N&#8217;UPDATE STATISTICS [' + USER_NAME(uid) + N'].[' + so1.name + N'] WITH FULLSCAN&#8217; AS Command,<br />
	(SELECT SUM(dpages) FROM dbo.sysindexes si1 WHERE id = so1.id) * 0.40 AS ItemWork<br />
FROM<br />
	dbo.sysobjects so1<br />
LEFT OUTER JOIN<br />
	#ReindexCandidate rc1<br />
	ON<br />
		(<br />
			rc1.ObjectId = so1.id<br />
			AND<br />
			rc1.IndexId = 1<br />
		)<br />
WHERE<br />
	so1.xtype = &#8216;U&#8217;<br />
	AND<br />
	rc1.ObjectId IS NULL<br />
	AND<br />
	(SELECT SUM(dpages) FROM dbo.sysindexes si1 WHERE id = so1.id)  0<br />
	AND<br />
	so1.id  OBJECT_ID(&#8216;dbo.DBMaint_Task&#8217;)</p>
<p>DELETE FROM<br />
	dbo.DBMaint_Task<br />
WHERE<br />
	ItemWork = 0</p>
<p>&#8211; Break all ties by ItemWork<br />
&#8211; This algorithm is arbitrary, but the amount of estimated work it adds is trival<br />
SET @RowsUpdated = 1<br />
WHILE @RowsUpdated  0<br />
BEGIN<br />
	UPDATE<br />
		mt1<br />
	SET<br />
		ItemWork = ItemWork + 0.01<br />
	FROM<br />
		dbo.DBMaint_Task mt1<br />
	INNER JOIN<br />
		(<br />
			SELECT<br />
				MAX(MaintTaskId) AS MaintTaskId<br />
			FROM<br />
				dbo.DBMaint_Task<br />
			GROUP BY<br />
				ItemWork<br />
			HAVING<br />
				COUNT(*) &gt; 1<br />
		) mt2<br />
	ON<br />
		(<br />
			mt1.MaintTaskId = mt2.MaintTaskId<br />
		)</p>
<p>	SET @RowsUpdated = @@ROWCOUNT<br />
END		</p>
<p>SET @CurrentInterval = 1<br />
WHILE @CurrentInterval = mt1.ItemWork<br />
				AND<br />
				mt2.Interval = -1<br />
		) &lt;= @WorkPerIntervalGoal	</p>
<p>	SET @RowsUpdated = @@ROWCOUNT</p>
<p>	IF @RowsUpdated = 0<br />
	BEGIN<br />
		UPDATE<br />
			mt1<br />
		SET<br />
			Interval = @CurrentInterval<br />
		FROM<br />
			dbo.DBMaint_Task mt1<br />
		WHERE<br />
		mt1.ItemWork = (<br />
			SELECT<br />
				MAX(mt2.ItemWork)<br />
			FROM<br />
				dbo.DBMaint_Task mt2<br />
			WHERE<br />
				mt2.Interval = -1<br />
		)<br />
	END</p>
<p>	SET @CurrentInterval = @CurrentInterval + 1<br />
END</p>
<p>SET NOCOUNT OFF</p>
<p>GO</p>
<p>IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(&#039;dbo.p_maint_ExecuteMaintTasks&#039;) AND xtype = &#039;P&#039;)<br />
BEGIN<br />
	DROP PROCEDURE dbo.p_maint_ExecuteMaintTasks<br />
END<br />
GO</p>
<p>CREATE PROCEDURE dbo.p_maint_ExecuteMaintTasks<br />
	@PeriodLength 			int = 7,	&#8211; Number of intervals in a period<br />
	@IndexRebuildThreshold		int = 10,	&#8211; Maximum LogicalFragmentation value allowed before an index is rebuilt<br />
	@ForceInterval			int = NULL,	&#8211; Manually set the current interval rather than calculating it from the date<br />
	@ForceRebuildTaskList 		int = 0,	&#8211; If non-zero, force a rebuild of the task list<br />
	@RebuildTaskListInterval	int = 1		&#8211; The interval in which to automatically rebuild the task list<br />
AS</p>
<p>DECLARE @CurrentInterval	 	int<br />
DECLARE @TaskCount			int<br />
DECLARE @Command			nvarchar(4000)<br />
DECLARE @MaintTaskId			int</p>
<p>SET NOCOUNT ON</p>
<p>IF @PeriodLength &lt; 1<br />
BEGIN<br />
	RAISERROR(N&#039;@PeriodLength must be greater than zero.&#039;, 16, 1)<br />
	RETURN<br />
END</p>
<p>IF @ForceInterval IS NOT NULL<br />
BEGIN<br />
	IF @ForceInterval  @PeriodLength<br />
	BEGIN<br />
		RAISERROR(N&#8217;If not null, @ForceInterval must be less than or equal to @PeriodLength.&#8217;, 16, 1)<br />
		RETURN<br />
	END<br />
END</p>
<p>IF @RebuildTaskListInterval &gt; @PeriodLength<br />
BEGIN<br />
	RAISERROR(N&#8217;@RebuildTaskListInterval must be less than or equal to @PeriodLength.&#8217;, 16, 1)<br />
	RETURN<br />
END</p>
<p>IF NOT @IndexRebuildThreshold BETWEEN 0 AND 100<br />
BEGIN<br />
	RAISERROR(N&#8217;@IndexRebuildThreshold must be between 0 and 100.&#8217;, 16, 1)<br />
	RETURN<br />
END</p>
<p>SELECT<br />
	@TaskCount = COUNT(*)<br />
FROM<br />
	dbo.DBMaint_Task<br />
WHERE<br />
	CompletedDatetime IS NULL</p>
<p>IF @ForceInterval IS NULL<br />
BEGIN<br />
	SELECT<br />
		@CurrentInterval = ((YEAR(GETDATE() &#8211; 59) * 365 + DATEPART(dy, GETDATE() &#8211; 59)) % @PeriodLength) + 1<br />
END<br />
ELSE<br />
BEGIN<br />
	SELECT<br />
		@CurrentInterval = @ForceInterval<br />
END</p>
<p>IF @TaskCount = 0 OR @ForceRebuildTaskList  0 OR @CurrentInterval = @RebuildTaskListInterval<br />
BEGIN<br />
	EXEC dbo.p_maint_ScheduleMaintTasks<br />
		@PeriodLength = @PeriodLength,<br />
		@IndexRebuildThreshold = @IndexRebuildThreshold<br />
END</p>
<p>DECLARE csr_Task CURSOR FAST_FORWARD FOR<br />
SELECT<br />
	MaintTaskId,<br />
	Command<br />
FROM<br />
	dbo.DBMaint_Task<br />
WHERE<br />
	Interval = @CurrentInterval<br />
	AND<br />
	CompletedDatetime IS NULL</p>
<p>OPEN csr_Task</p>
<p>FETCH NEXT FROM csr_Task INTO @MaintTaskId, @Command<br />
WHILE @@FETCH_STATUS = 0<br />
BEGIN<br />
	PRINT CONVERT(nvarchar(30), GETDATE(), 121) + N&#8217;: Executing &#8220;&#8216; + @Command + N&#8217;&#8221;&#8216;<br />
	EXEC(@Command)<br />
	PRINT &#8221;</p>
<p>	UPDATE<br />
		dbo.DBMaint_Task<br />
	SET<br />
		CompletedDatetime = GETDATE()<br />
	WHERE<br />
		MaintTaskId = @MaintTaskId</p>
<p>	FETCH NEXT FROM csr_Task INTO @MaintTaskId, @Command<br />
END</p>
<p>CLOSE csr_Task<br />
DEALLOCATE csr_Task</p>
<p>SET NOCOUNT OFF<br />
GO</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Gmamata</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5051</link>
		<dc:creator>Gmamata</dc:creator>
		<pubDate>Sat, 30 Jan 2010 20:38:03 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5051</guid>
		<description>Hi Michelle,

Is this latest version of the script that has addressed some of the issues by users (like Derick and SuperCoolMoss pointed about the stats rebuild feature in your defrag script will only complete for one database.)?

Thank you</description>
		<content:encoded><![CDATA[<p>Hi Michelle,</p>
<p>Is this latest version of the script that has addressed some of the issues by users (like Derick and SuperCoolMoss pointed about the stats rebuild feature in your defrag script will only complete for one database.)?</p>
<p>Thank you</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5045</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Tue, 26 Jan 2010 17:44:52 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5045</guid>
		<description>@Carol I haven&#039;t been able to duplicate the issue you mention, although I&#039;m not entirely sure I understand what&#039;s happening, either.  Any input would be appreciated.

I don&#039;t think it&#039;ll work with a database compatibility level = 80.  

Thanks for your comments!  :)</description>
		<content:encoded><![CDATA[<p>@Carol I haven&#8217;t been able to duplicate the issue you mention, although I&#8217;m not entirely sure I understand what&#8217;s happening, either.  Any input would be appreciated.</p>
<p>I don&#8217;t think it&#8217;ll work with a database compatibility level = 80.  </p>
<p>Thanks for your comments!  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5044</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Tue, 26 Jan 2010 16:49:38 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5044</guid>
		<description>@Chris Sorry, this version only works with SQL Server 2005 and above because of its extensive use of DMV&#039;s.</description>
		<content:encoded><![CDATA[<p>@Chris Sorry, this version only works with SQL Server 2005 and above because of its extensive use of DMV&#8217;s.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5043</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Tue, 26 Jan 2010 16:47:09 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5043</guid>
		<description>@dhjackal sp_updatestats will only update the statistics that need it.  So it&#039;s just as easy and possibly more of a catch-all to run it for all objects in the database.

The reason I don&#039;t include a FILL FACTOR is I can&#039;t think of an occasion where I would ever want to bulk-change the FILL FACTOR setting for all indexes.  Right now, I consider the script fairly harmless, but I would consider that a potential accident waiting to happen if someone were not aware of what he/she was doing, set the value, and ran it for all databases and tables.</description>
		<content:encoded><![CDATA[<p>@dhjackal sp_updatestats will only update the statistics that need it.  So it&#8217;s just as easy and possibly more of a catch-all to run it for all objects in the database.</p>
<p>The reason I don&#8217;t include a FILL FACTOR is I can&#8217;t think of an occasion where I would ever want to bulk-change the FILL FACTOR setting for all indexes.  Right now, I consider the script fairly harmless, but I would consider that a potential accident waiting to happen if someone were not aware of what he/she was doing, set the value, and ran it for all databases and tables.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Michelle Ufford</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5042</link>
		<dc:creator>Michelle Ufford</dc:creator>
		<pubDate>Tue, 26 Jan 2010 16:42:38 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5042</guid>
		<description>@Gmamata yes, you can create the table and proc in the Master database, but I typically recommend the creation of a database for DBA-related administration.  I typically call mine something like &quot;DBA_Sandbox.&quot;</description>
		<content:encoded><![CDATA[<p>@Gmamata yes, you can create the table and proc in the Master database, but I typically recommend the creation of a database for DBA-related administration.  I typically call mine something like &#8220;DBA_Sandbox.&#8221;</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Gmamata</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5041</link>
		<dc:creator>Gmamata</dc:creator>
		<pubDate>Mon, 25 Jan 2010 19:06:42 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5041</guid>
		<description>Can we create these tables &amp; procedures in Master database? Or do we need to create a separate Admin database &amp; create the above tables &amp; procedures?

what is the best method

thanks</description>
		<content:encoded><![CDATA[<p>Can we create these tables &amp; procedures in Master database? Or do we need to create a separate Admin database &amp; create the above tables &amp; procedures?</p>
<p>what is the best method</p>
<p>thanks</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: dhjackal</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5039</link>
		<dc:creator>dhjackal</dc:creator>
		<pubDate>Thu, 07 Jan 2010 10:59:41 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5039</guid>
		<description>Hi Michelle,

Excellent procedure and thanks for sharing it with us. 

I&#039;ve used it as the basis for all of my index defragmentation management across all of my production servers. I call it slightly differently though. I use a &quot;wrapper&quot; procedure (usp_ProcRunner) to call all of my procedures / functions and I pass a list of databases that I want the proc to run against into this which subsequently passes it down to the called proc. 

i.e. 

EXEC DBA_Development.dbo.usp_ProcRunner
	  @Databases = &#039;database1, database2&#039;  -- Can be USER, SYSTEM, ALL or a list of databases
	, @ProcCall = &#039;EXECUTE DBA_Development.dbo.usp_IndexDefrag @minFragmentation = 5, @rebuildThreshold = 30, @maxDopRestriction = 2&#039;
	, @DebugMode = &#039;N&#039;
GO

I too have opted to include the SORT_IN_TEMPDB option to the rebuild index statement. 

I have a couple of queries.

1) Any reason why you don&#039;t just update the statistics for the objects that are reorganised rather than all the objects in the db?

2) You don&#039;t include a FILL_FACTOR in your rebuild statement. Any particular reason for this?</description>
		<content:encoded><![CDATA[<p>Hi Michelle,</p>
<p>Excellent procedure and thanks for sharing it with us. </p>
<p>I&#8217;ve used it as the basis for all of my index defragmentation management across all of my production servers. I call it slightly differently though. I use a &#8220;wrapper&#8221; procedure (usp_ProcRunner) to call all of my procedures / functions and I pass a list of databases that I want the proc to run against into this which subsequently passes it down to the called proc. </p>
<p>i.e. </p>
<p>EXEC DBA_Development.dbo.usp_ProcRunner<br />
	  @Databases = &#8216;database1, database2&#8242;  &#8212; Can be USER, SYSTEM, ALL or a list of databases<br />
	, @ProcCall = &#8216;EXECUTE DBA_Development.dbo.usp_IndexDefrag @minFragmentation = 5, @rebuildThreshold = 30, @maxDopRestriction = 2&#8242;<br />
	, @DebugMode = &#8216;N&#8217;<br />
GO</p>
<p>I too have opted to include the SORT_IN_TEMPDB option to the rebuild index statement. </p>
<p>I have a couple of queries.</p>
<p>1) Any reason why you don&#8217;t just update the statistics for the objects that are reorganised rather than all the objects in the db?</p>
<p>2) You don&#8217;t include a FILL_FACTOR in your rebuild statement. Any particular reason for this?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Carol Noel</title>
		<link>http://sqlfool.com/2009/06/index-defrag-script-v30/comment-page-2/#comment-5038</link>
		<dc:creator>Carol Noel</dc:creator>
		<pubDate>Thu, 24 Dec 2009 02:30:14 +0000</pubDate>
		<guid isPermaLink="false">http://sqlfool.com/?p=1072#comment-5038</guid>
		<description>Hi Michelle:
This is fantastic. I have been testing and will deploy.  A few things - 

1) Noticed same minor problem posted above by Vic Prahu on Wed, 24th Jun 2009 2:01 pm.  Seems to happen when a table has more that one index selected for defrag.

2) can this script be used for databases on a SQL2K5 box with compatability level 80 ? 

3) I modified code a bit to exclude processing of an entire database.  Modified the exclusion table a bit as well to handle this.   

Looking forward to next enhancements.</description>
		<content:encoded><![CDATA[<p>Hi Michelle:<br />
This is fantastic. I have been testing and will deploy.  A few things &#8211; </p>
<p>1) Noticed same minor problem posted above by Vic Prahu on Wed, 24th Jun 2009 2:01 pm.  Seems to happen when a table has more that one index selected for defrag.</p>
<p>2) can this script be used for databases on a SQL2K5 box with compatability level 80 ? </p>
<p>3) I modified code a bit to exclude processing of an entire database.  Modified the exclusion table a bit as well to handle this.   </p>
<p>Looking forward to next enhancements.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
