Showing posts with label execute. Show all posts
Showing posts with label execute. Show all posts

Tuesday, March 20, 2012

Planning execution of package

How can i plan the execution of a package ?

For exemple, i want to execute it every 5 minutes from 8 AM to 20 PM

ThanksSQL Agent provides scheduled execution times etc. you can use to do such things.
Right click on the Agent node in Management Studio, select new job. Select the schedule tab and note that there are ways to schedule a job daily, and then sub obtions allow you to execute every x minutes or hours.|||

Great ! it works fine

|||Out of interest, what is it actually doing?

I'm just thinking that in some circumstances maybe it might be better to execute a package when some event occurs rather than continuously executing at defined intervals waiting for something to happen (if indeed this is what it is doing).

Another option might be the WMI EventWatcher task.

Just speculating of course...

-Jamie|||I use it to download stock quotes published on http server...|||Fair enough. SQL Agent is probably your best option then. I'll shutup now Smile

|||Smile I'm beginner then i listen everyone... your remarks are welcome....

ps : excuse my french accent...|||

Coroebus wrote:

Smile I'm beginner then i listen everyone... your remarks are welcome....

ps : excuse my french accent...

Your english is alot better than that of other people I have seen on many technical forums that speak it as their first language. Don't worry about that!

Plan Maintenance will not execute

My plan Maintenance to Optimize, TRN Backup and Reporting
has been running for several months. A few days ago, I
started getting the following in "View Job History":
"Executed as user: domain\Administrator. sqlmaint.exe
failed. [SQLSTATE 42000] (Error 22029). The step failed."
There is no log file created, even though I requested one,
which leads me to believe the Job never actually started.
The Windows 2000 Applications Log has the following:
"SQL Server Scheduled Job 'Optimizations Job for DB
Maintenance Plan 'Test 1''
(0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
Invoked on: 2004-07-14 22:30:00 - Message: The job
failed. The Job was invoked by Schedule 42 (Schedule 1).
The last step to run was step 1 (Step 1)."
When I try and run the command in Query Analyzer, I get
the following:
"Server: Msg 22029, Level 16, State 1, Line 0
sqlmaint.exe failed."
The recovery model is "Bulk-Logged"
Does anyone have any Idea what has gone wrong in this
maintenance Plan?Hi,
By any chance did you changed the recovery model for a database to SIMPLE
and then turned back to BULK_LOGGED. In this
case you have to do a FULL database backup for that database.
command:
--
BACKUP database <dbname> to disk='d:\backup\dbname.bak' with init
Thanks
Hari
MCDBA
"Ken Bitner" <anonymous@.discussions.microsoft.com> wrote in message
news:2d53601c46a17$38dd0f20$a501280a@.phx
.gbl...
> My plan Maintenance to Optimize, TRN Backup and Reporting
> has been running for several months. A few days ago, I
> started getting the following in "View Job History":
> "Executed as user: domain\Administrator. sqlmaint.exe
> failed. [SQLSTATE 42000] (Error 22029). The step failed."
> There is no log file created, even though I requested one,
> which leads me to believe the Job never actually started.
> The Windows 2000 Applications Log has the following:
> "SQL Server Scheduled Job 'Optimizations Job for DB
> Maintenance Plan 'Test 1''
> (0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
> Invoked on: 2004-07-14 22:30:00 - Message: The job
> failed. The Job was invoked by Schedule 42 (Schedule 1).
> The last step to run was step 1 (Step 1)."
> When I try and run the command in Query Analyzer, I get
> the following:
> "Server: Msg 22029, Level 16, State 1, Line 0
> sqlmaint.exe failed."
> The recovery model is "Bulk-Logged"
> Does anyone have any Idea what has gone wrong in this
> maintenance Plan?
>
>|||No. The Recovery Model has always been "Bulk-Logged".
Also, I have take a full backup every day via the same
command you sent me.

>--Original Message--
>Hi,
>By any chance did you changed the recovery model for a
database to SIMPLE
>and then turned back to BULK_LOGGED. In this
>case you have to do a FULL database backup for that
database.
>command:
>--
>BACKUP database <dbname> to disk='d:\backup\dbname.bak'
with init
>
>--
>Thanks
>Hari
>MCDBA
>
>"Ken Bitner" <anonymous@.discussions.microsoft.com> wrote
in message
> news:2d53601c46a17$38dd0f20$a501280a@.phx
.gbl...
Reporting[vbcol=seagreen]
failed."[vbcol=seagreen]
one,[vbcol=seagreen]
started.[vbcol=seagreen]
1).[vbcol=seagreen]
>
>.
>

Plan Maintenance will not execute

My plan Maintenance to Optimize, TRN Backup and Reporting
has been running for several months. A few days ago, I
started getting the following in "View Job History":
"Executed as user: domain\Administrator. sqlmaint.exe
failed. [SQLSTATE 42000] (Error 22029). The step failed."
There is no log file created, even though I requested one,
which leads me to believe the Job never actually started.
The Windows 2000 Applications Log has the following:
"SQL Server Scheduled Job 'Optimizations Job for DB
Maintenance Plan 'Test 1''
(0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
Invoked on: 2004-07-14 22:30:00 - Message: The job
failed. The Job was invoked by Schedule 42 (Schedule 1).
The last step to run was step 1 (Step 1)."
When I try and run the command in Query Analyzer, I get
the following:
"Server: Msg 22029, Level 16, State 1, Line 0
sqlmaint.exe failed."
The recovery model is "Bulk-Logged"
Does anyone have any Idea what has gone wrong in this
maintenance Plan?
Hi,
By any chance did you changed the recovery model for a database to SIMPLE
and then turned back to BULK_LOGGED. In this
case you have to do a FULL database backup for that database.
command:
BACKUP database <dbname> to disk='d:\backup\dbname.bak' with init
Thanks
Hari
MCDBA
"Ken Bitner" <anonymous@.discussions.microsoft.com> wrote in message
news:2d53601c46a17$38dd0f20$a501280a@.phx.gbl...
> My plan Maintenance to Optimize, TRN Backup and Reporting
> has been running for several months. A few days ago, I
> started getting the following in "View Job History":
> "Executed as user: domain\Administrator. sqlmaint.exe
> failed. [SQLSTATE 42000] (Error 22029). The step failed."
> There is no log file created, even though I requested one,
> which leads me to believe the Job never actually started.
> The Windows 2000 Applications Log has the following:
> "SQL Server Scheduled Job 'Optimizations Job for DB
> Maintenance Plan 'Test 1''
> (0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
> Invoked on: 2004-07-14 22:30:00 - Message: The job
> failed. The Job was invoked by Schedule 42 (Schedule 1).
> The last step to run was step 1 (Step 1)."
> When I try and run the command in Query Analyzer, I get
> the following:
> "Server: Msg 22029, Level 16, State 1, Line 0
> sqlmaint.exe failed."
> The recovery model is "Bulk-Logged"
> Does anyone have any Idea what has gone wrong in this
> maintenance Plan?
>
>
|||No. The Recovery Model has always been "Bulk-Logged".
Also, I have take a full backup every day via the same
command you sent me.

>--Original Message--
>Hi,
>By any chance did you changed the recovery model for a
database to SIMPLE
>and then turned back to BULK_LOGGED. In this
>case you have to do a FULL database backup for that
database.
>command:
>--
>BACKUP database <dbname> to disk='d:\backup\dbname.bak'
with init
>
>--
>Thanks
>Hari
>MCDBA
>
>"Ken Bitner" <anonymous@.discussions.microsoft.com> wrote
in message[vbcol=seagreen]
>news:2d53601c46a17$38dd0f20$a501280a@.phx.gbl...
Reporting[vbcol=seagreen]
failed."[vbcol=seagreen]
one,[vbcol=seagreen]
started.[vbcol=seagreen]
1).
>
>.
>

Plan Maintenance will not execute

My plan Maintenance to Optimize, TRN Backup and Reporting
has been running for several months. A few days ago, I
started getting the following in "View Job History":
"Executed as user: domain\Administrator. sqlmaint.exe
failed. [SQLSTATE 42000] (Error 22029). The step failed."
There is no log file created, even though I requested one,
which leads me to believe the Job never actually started.
The Windows 2000 Applications Log has the following:
"SQL Server Scheduled Job 'Optimizations Job for DB
Maintenance Plan 'Test 1''
(0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
Invoked on: 2004-07-14 22:30:00 - Message: The job
failed. The Job was invoked by Schedule 42 (Schedule 1).
The last step to run was step 1 (Step 1)."
When I try and run the command in Query Analyzer, I get
the following:
"Server: Msg 22029, Level 16, State 1, Line 0
sqlmaint.exe failed."
The recovery model is "Bulk-Logged"
Does anyone have any Idea what has gone wrong in this
maintenance Plan?Hi,
By any chance did you changed the recovery model for a database to SIMPLE
and then turned back to BULK_LOGGED. In this
case you have to do a FULL database backup for that database.
command:
--
BACKUP database <dbname> to disk='d:\backup\dbname.bak' with init
Thanks
Hari
MCDBA
"Ken Bitner" <anonymous@.discussions.microsoft.com> wrote in message
news:2d53601c46a17$38dd0f20$a501280a@.phx.gbl...
> My plan Maintenance to Optimize, TRN Backup and Reporting
> has been running for several months. A few days ago, I
> started getting the following in "View Job History":
> "Executed as user: domain\Administrator. sqlmaint.exe
> failed. [SQLSTATE 42000] (Error 22029). The step failed."
> There is no log file created, even though I requested one,
> which leads me to believe the Job never actually started.
> The Windows 2000 Applications Log has the following:
> "SQL Server Scheduled Job 'Optimizations Job for DB
> Maintenance Plan 'Test 1''
> (0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
> Invoked on: 2004-07-14 22:30:00 - Message: The job
> failed. The Job was invoked by Schedule 42 (Schedule 1).
> The last step to run was step 1 (Step 1)."
> When I try and run the command in Query Analyzer, I get
> the following:
> "Server: Msg 22029, Level 16, State 1, Line 0
> sqlmaint.exe failed."
> The recovery model is "Bulk-Logged"
> Does anyone have any Idea what has gone wrong in this
> maintenance Plan?
>
>|||No. The Recovery Model has always been "Bulk-Logged".
Also, I have take a full backup every day via the same
command you sent me.
>--Original Message--
>Hi,
>By any chance did you changed the recovery model for a
database to SIMPLE
>and then turned back to BULK_LOGGED. In this
>case you have to do a FULL database backup for that
database.
>command:
>--
>BACKUP database <dbname> to disk='d:\backup\dbname.bak'
with init
>
>--
>Thanks
>Hari
>MCDBA
>
>"Ken Bitner" <anonymous@.discussions.microsoft.com> wrote
in message
>news:2d53601c46a17$38dd0f20$a501280a@.phx.gbl...
>> My plan Maintenance to Optimize, TRN Backup and
Reporting
>> has been running for several months. A few days ago, I
>> started getting the following in "View Job History":
>> "Executed as user: domain\Administrator. sqlmaint.exe
>> failed. [SQLSTATE 42000] (Error 22029). The step
failed."
>> There is no log file created, even though I requested
one,
>> which leads me to believe the Job never actually
started.
>> The Windows 2000 Applications Log has the following:
>> "SQL Server Scheduled Job 'Optimizations Job for DB
>> Maintenance Plan 'Test 1''
>> (0x529723559D047845AB998AFF9BDA397F) - Status: Failed -
>> Invoked on: 2004-07-14 22:30:00 - Message: The job
>> failed. The Job was invoked by Schedule 42 (Schedule
1).
>> The last step to run was step 1 (Step 1)."
>> When I try and run the command in Query Analyzer, I get
>> the following:
>> "Server: Msg 22029, Level 16, State 1, Line 0
>> sqlmaint.exe failed."
>> The recovery model is "Bulk-Logged"
>> Does anyone have any Idea what has gone wrong in this
>> maintenance Plan?
>>
>
>.
>

Monday, March 12, 2012

Place a triiger on sysprocesses table

Hi,
I have to set up a trigger on master database sysprocesses, but when I
execute the trigger, I got an error, says "CREATE TRIGGER permission denied
on object 'sysprocesses', database 'master', owner 'dbo'." Can anybody help
me on this?
ThanksYou cannot create triggers on system tables. If you post what you want to achieve, perhaps someone
can reply with a suggestion.
--
Tibor Karaszi, SQL Server MVP
http://www.karaszi.com/sqlserver/default.asp
http://www.solidqualitylearning.com/
"Hong Wang" <HongWang@.discussions.microsoft.com> wrote in message
news:7515D739-3472-4D43-9D81-80E1C0744893@.microsoft.com...
> Hi,
> I have to set up a trigger on master database sysprocesses, but when I
> execute the trigger, I got an error, says "CREATE TRIGGER permission denied
> on object 'sysprocesses', database 'master', owner 'dbo'." Can anybody help
> me on this?
> Thanks|||Triggers are not supported on system tables. What exactly are you trying to
achieve?
--
Vyas, MVP (SQL Server)
SQL Server Articles and Code Samples @. http://vyaskn.tripod.com/
"Hong Wang" <HongWang@.discussions.microsoft.com> wrote in message
news:7515D739-3472-4D43-9D81-80E1C0744893@.microsoft.com...
> Hi,
> I have to set up a trigger on master database sysprocesses, but when I
> execute the trigger, I got an error, says "CREATE TRIGGER permission
denied
> on object 'sysprocesses', database 'master', owner 'dbo'." Can anybody
help
> me on this?
> Thanks|||I need to audit the sysprocesses table, and if somebody is using MS Access to
modify any data on the server, then send out Email alert and kill the
process. Any idea how can I do this without using a trigger?
Thanks.
"Narayana Vyas Kondreddi" wrote:
> Triggers are not supported on system tables. What exactly are you trying to
> achieve?
> --
> Vyas, MVP (SQL Server)
> SQL Server Articles and Code Samples @. http://vyaskn.tripod.com/
>
> "Hong Wang" <HongWang@.discussions.microsoft.com> wrote in message
> news:7515D739-3472-4D43-9D81-80E1C0744893@.microsoft.com...
> > Hi,
> >
> > I have to set up a trigger on master database sysprocesses, but when I
> > execute the trigger, I got an error, says "CREATE TRIGGER permission
> denied
> > on object 'sysprocesses', database 'master', owner 'dbo'." Can anybody
> help
> > me on this?
> >
> > Thanks
>
>|||Just because they connect to the server doesn't mean they are going to
change data. I would suggest you do not allow those particular logins
access the database. Why give them access if you are trying to prevent
it?
If OTOH you are saying that the user requires access to the database
from certain applications, but not others, you might consider using
Application Roles (see Application Roles and sp_addapprole in BOL for
more information).
David Gugick
Imceda Software
www.imceda.com|||This is for SOX audit. I have to provide a way to prove that if anyone did
get into certain data without using the application front end, we can catch
it.
"David Gugick" wrote:
> Just because they connect to the server doesn't mean they are going to
> change data. I would suggest you do not allow those particular logins
> access the database. Why give them access if you are trying to prevent
> it?
> If OTOH you are saying that the user requires access to the database
> from certain applications, but not others, you might consider using
> Application Roles (see Application Roles and sp_addapprole in BOL for
> more information).
>
> --
> David Gugick
> Imceda Software
> www.imceda.com
>|||As David said, look at application roles. If that's not an option, take a
look at APP_NAME() and USER_NAME and few other similar functions to find the
current user name and application name (session based)...
Example:
DECLARE @.CurrentApp varchar(35)
SET @.CurrentApp = APP_NAME()
IF @.CurrentApp <> 'MS SQL Query Analyzer'
PRINT 'This process was not started by a SQL Query Analyzer query session.'
--
Sasan Saidi, MSc in cs
Senior DBA
Brascan Business Services
"I saw it work in a cartoon once so I am pretty sure I can do it."
"Hong Wang" wrote:
> This is for SOX audit. I have to provide a way to prove that if anyone did
> get into certain data without using the application front end, we can catch
> it.
> "David Gugick" wrote:
> > Just because they connect to the server doesn't mean they are going to
> > change data. I would suggest you do not allow those particular logins
> > access the database. Why give them access if you are trying to prevent
> > it?
> >
> > If OTOH you are saying that the user requires access to the database
> > from certain applications, but not others, you might consider using
> > Application Roles (see Application Roles and sp_addapprole in BOL for
> > more information).
> >
> >
> > --
> > David Gugick
> > Imceda Software
> > www.imceda.com
> >
> >

Friday, March 9, 2012

Pkg Execution Works in VS but not in SQL

I'm able to execute a package in VS Pro on my machine. However when I upload it to the sql server and try to execute the package directly it fails with:

Error: The product level is insuficient for component "...." (3129)
Error: The product level is insuficient for component "...." (5411)

The first component is a DataReader Source which is consuming an ODBC (Noble Systems ATOMIX Driver) connection and the second component is a DataConversion object. Anyone know why this would work running it on my pc in VS but not when I execute it from SQL on the same machine?

This is a silly question but are SSIS components installed on your sql server?

The error message looks similar to an error message I had once. I was trying to execute maintenance plans (which uses SSIS) and I had not installed the components.

|||

Jason's suggeston is a good one. You only need to install client components off the CD in order to build packages. You need to install SSIS to execute them outside of BIDS/VS.

-Jamie

|||

Yes, SSIS is installed. I can log into the service and can successfully run and schedule 'hello world' packages. As a developer I'm locked out of this system but I am trying to get access to the app logs to see if they reveal something.

I'm really at a loss. Since I'm executing the package it should be using the odbc driver from my pc as well as the dsn config right? Based on my description of the objects that threw the error(s) am I trying to use a feature that is only available in the enterprise edition?

|||

How are you executing the package?

Donald

|||

from within SMS-->Stored Packages-->MSDB--><Subfolder>--><MyPackage>

I right click on package and select Run Package.

thanks,
Scott

|||All components work in VS reguardless of the version required to run those components. The version checks come in only when you run the package outside the VS environment. What version of SSIS is installed on the server?|||

v.9.0.1399 (pre SP1)

|||Sorry, what product level. Also, list all the types of components in the entire package.|||

Ah, sorry about that.

All of the following components are installed on a single Win3k server (flavor and sp level n/a but I can find out if necessary) Sql standard edition:

Database Engine
SSIS
SSRS

|||

One - I got this message when running the package on my local machine with Enterprise Manager connected to the server.To fix this, you need to install the SSIS Service on your local machine. When you installed SQL 2005, you only installed the workstation components and the workstation product level is missing some components. Installing the SSIS Service will include the components needed to run SSIS on your local machine.

Two - If you are remote in to your server and you are getting this message, then you might have a Fuzzy lookup task that only works with the Enterprise Edition.

Hope that help.

|||Does anyone know if this will be a licensing issue?|||

Installing the SSIS component locally on my machine resolved this issue. However, I'm concerned about this behavior (i.e. not being able to execute a package that is on a server from a remote machine via Mgt Studio).

Maybe someone at Microsoft can answer this:

If I have a full install of the client tools and even a full install of VS05 Pro, why do I need to explicity installl the SSIS server component on my local machine to run packages located on a remote server (sql 2005 standard w/out sp1)? I spent a lot of time troubleshooting this error (as did a number of members of this forum) and I can't help but think that this should have worked out of the box.

PK still shows fragmentation after ALTER INDEX.. REBUILD

I am using sys.dm_db_index_physical_stats to identify indexes that need to be rebuilt based on a fragmentation limit. Once identified, I execute and ALTER INDEX... REBUILD on the index. If the index is clustered, only that index gets rebuilt for the table. After all the indexes are complete, I receive a report on the indexes that were rebuilt in the databases and what level of fragmentation the index was at before rebuilt. After checking these indexes, I still see that all the Primary Key indexes are still at the same fragmentation level. I run the process again and it does not change. I updated table usage and also ran update statistics after running the rebuild again, but the fragmentation does not change. Why can’t these PK Clustered indexes be rebuilt as expected? Do I need to drop and recreate the PK before this fragmentation changes?

How are you measuring the extent of the fragmentation?

Thanks

ray

|||I run sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) again to see the fragmentation. I also run DBCC SHOWCONTIG with the same results.|||

Can you please post the results of the DBCC SHOWCONTIG statement?

Thanks

Ray

|||

Results from: sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) -- Note, I added table names and Index names to the result set

TableID ,TableName, IndexID ,IndexName ,Fragmentation

87671360, [MyTable], 1 ,[MyIndex] ,83.3333333333333

Results from: DBCC SHOWCONTIG (87671360,1)

DBCC SHOWCONTIG scanning 'MyTable' table...

Table: 'MyTable' (87671360); index ID: 1, database ID: 10

TABLE level scan performed.

- Pages Scanned................................: 6

- Extents Scanned..............................: 6

- Extent Switches..............................: 5

- Avg. Pages per Extent........................: 1.0

- Scan Density [Best Count:Actual Count].......: 16.67% [1:6]

- Logical Scan Fragmentation ..................: 83.33%

- Extent Scan Fragmentation ...................: 83.33%

- Avg. Bytes Free per Page.....................: 387.8

- Avg. Page Density (full).....................: 95.21%

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

|||

Here is the code that I put in a proc but it can be run in any non sys databases. the only thing is it does create a permanent table for reporting but you can drop it any time.

SET NOCOUNT ON;

DECLARE @.v_Object_Id int;

DECLARE @.v_Index_Id int;

DECLARE @.v_Schema_Nm nvarchar(130);

DECLARE @.v_Object_Nm nvarchar(130);

DECLARE @.v_Index_Nm nvarchar(130);

DECLARE @.v_Rebuild_Stmt nvarchar(2000);

DECLARE @.v_Frag_Flt float

DECLARE @.v_Start_DtTm datetime;

DECLARE @.v_End_DtTm datetime;

DECLARE @.v_Duration_DtTm datetime;

--Uncomment if you are running the code and not the procedure

DECLARE @.ip_Frag_Limit Int

SET @.ip_Frag_Limit = 30

IF (((SELECT DB_NAME(DB_ID())) = 'master') OR ((SELECT DB_NAME(DB_ID())) = 'model') OR ((SELECT DB_NAME(DB_ID())) = 'msdb') OR ((SELECT DB_NAME(DB_ID())) = 'tempdb'))

BEGIN

PRINT 'You cannot execute this procedure in this database'

RETURN;

END

-- We want records in a permenant table so we see if it exists from a previous run

-- If it does exist, then we TRUNCATE it, otherwise, we create it

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DBA_IndexStatistics]') AND type in (N'U'))

TRUNCATE TABLE [dbo].[DBA_IndexStatistics]

ELSE

CREATE TABLE [dbo].[DBA_IndexStatistics](

[Object_Id] int NULL,

[Table_Nm] varchar(255) NULL,

[Index_Id] int NULL,

[Index_Nm] varchar(255) NULL,

[Frag] float NULL,

[IndexRebuilt_Ind] BIT NULL,

[Start_DtTm] datetime NULL,

[End_DtTm] datetime NULL,

[Duration] varchar(20) NULL

) ON [PRIMARY]

-- Load our temporary working table that will contain all of our index information

SELECT object_id AS [Object_Id], CAST('' AS sysname) AS [Table_Nm], index_id AS [Index_Id], CAST('' AS sysname) AS [Index_Nm], avg_fragmentation_in_percent AS [Frag],0 AS [IndexRebuilt_Ind], GetDate() AS [Start_DtTm], GetDate() AS [End_DtTm], '00:00:00' AS [Duration]

INTO #Tmp_Index_Stats

FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL)

WHERE Index_ID > 0

ORDER BY [Object_Id],[Index_Id];

-- Create a cursor to run through each distinct table object_id from our working table

DECLARE cur_Object CURSOR FAST_FORWARD FOR SELECT DISTINCT [Object_Id] FROM #Tmp_Index_Stats ORDER BY [Object_Id]

OPEN cur_Object

FETCH NEXT FROM cur_Object INTO @.v_Object_Id

WHILE @.@.FETCH_STATUS = 0

BEGIN

-- Check to see if the table has a Clustered index AND has any other NonClustered index with fragmentation >= the limit passed in the procedure

IF ((SELECT MIN([Index_Id]) FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id) = 1) AND ((SELECT COUNT([Object_Id]) FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id AND [Frag] >= @.ip_Frag_Limit) > 0)

BEGIN

-- If true then rebuild the Clustered Index only

SELECT @.v_Object_Nm = QUOTENAME(o.name), @.v_Schema_Nm = QUOTENAME(s.name)

FROM sys.objects AS o

JOIN sys.schemas as s ON s.schema_id = o.schema_id

WHERE o.object_id = @.v_Object_Id;

SELECT @.v_Index_Nm = QUOTENAME(name)

FROM sys.indexes

WHERE object_id = @.v_Object_Id AND Index_ID = 1;

-- Set Start time before rebuild

SET @.v_Start_DtTm = GetDate()

--SET @.v_Rebuild_Stmt = N'ALTER INDEX ALL ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

SET @.v_Rebuild_Stmt = N'ALTER INDEX ' + @.v_Index_Nm + N' ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

EXEC sp_executesql @.v_Rebuild_Stmt

--PRINT @.v_Rebuild_Stmt

-- Set End Time and Duration after rebuild

SET @.v_End_DtTm = GetDate()

SET @.v_Duration_DtTm = (@.v_End_DtTm - @.v_Start_DtTm)

-- Update values in our temp table that we will store in the permenant table.

UPDATE #Tmp_Index_Stats SET [IndexRebuilt_Ind] = 1 WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Table_Nm] = @.v_Object_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Index_Nm] = @.v_Index_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Start_DtTm] = @.v_Start_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [End_DtTm] = @.v_End_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Duration] = CONVERT(Varchar(20),@.v_Duration_DtTm,108) WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

END

ELSE

-- In this case, we do not have a Clustered index. Then we need to check each individual NonClustered index for fragmentation limits

BEGIN

-- Get a list of NonClustered indexes for this one table object_id

DECLARE cur_Index CURSOR FAST_FORWARD FOR SELECT [Index_Id], [Frag] FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id ORDER BY [Index_Id]

OPEN cur_Index

FETCH NEXT FROM cur_Index into @.v_Index_Id, @.v_Frag_Flt

WHILE @.@.FETCH_STATUS = 0

BEGIN

-- Compare actual index fragmentation to our fragmentation limit passed in to the procedure.

IF @.v_Frag_Flt >= @.ip_Frag_Limit

-- If index is more fragmented than our limit then rebuild this index

BEGIN

SELECT @.v_Object_Nm = QUOTENAME(o.name), @.v_Schema_Nm = QUOTENAME(s.name)

FROM sys.objects AS o

JOIN sys.schemas as s ON s.schema_id = o.schema_id

WHERE o.object_id = @.v_Object_Id;

SELECT @.v_Index_Nm = QUOTENAME(name)

FROM sys.indexes

WHERE object_id = @.v_Object_Id AND Index_ID = @.v_Index_Id;

-- Set Start time before rebuild

SET @.v_Start_DtTm = GetDate()

SET @.v_Rebuild_Stmt = N'ALTER INDEX ' + @.v_Index_Nm + N' ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

EXEC sp_executesql @.v_Rebuild_Stmt

--PRINT @.v_Rebuild_Stmt

-- Set End Time and Duration after rebuild

SET @.v_End_DtTm = GetDate()

SET @.v_Duration_DtTm = (@.v_End_DtTm - @.v_Start_DtTm)

-- Update values in our temp table that we will store in the permenant table.

UPDATE #Tmp_Index_Stats SET [IndexRebuilt_Ind] = 1 WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Table_Nm] = @.v_Object_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Index_Nm] = @.v_Index_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Start_DtTm] = @.v_Start_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [End_DtTm] = @.v_End_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Duration] = CONVERT(Varchar(20),@.v_Duration_DtTm,108) WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

END

FETCH NEXT FROM cur_Index into @.v_Index_Id, @.v_Frag_Flt

END

CLOSE cur_Index

DEALLOCATE cur_Index

END

FETCH NEXT FROM cur_Object into @.v_Object_Id

END

CLOSE cur_Object

DEALLOCATE cur_Object

-- Populate our permamnet table for our viewing. we only want to see what was rebuilt and how long it took.

INSERT [DBA_IndexStatistics] SELECT [Object_Id], [Table_Nm], [Index_Id], [Index_Nm], [Frag], [IndexRebuilt_Ind], [Start_DtTm], [End_DtTm], [Duration] FROM #Tmp_Index_Stats WHERE [IndexRebuilt_Ind] = 1 ORDER BY [Duration] DESC

-- Drop our temporary table

DROP TABLE #Tmp_Index_Stats

SELECT * FROM [DBA_IndexStatistics] ORDER BY [Duration] DESC

|||

One thing i would say is that in SQL2005 rebuilding a clustered index does NOT rebuild all associated nonclustered indexes.

Would that explain the behaviour you are seeing?

|||No, I realized that. If you look at the code block for the Clustered Indexes, there is a line commented out that runs the ALTER INDEX ALL ON... However, this still shows that the Primary Key Clustered Indexes retain the same fragmentation levels.

PK still shows fragmentation after ALTER INDEX.. REBUILD

I am using sys.dm_db_index_physical_stats to identify indexes that need to be rebuilt based on a fragmentation limit. Once identified, I execute and ALTER INDEX... REBUILD on the index. If the index is clustered, only that index gets rebuilt for the table. After all the indexes are complete, I receive a report on the indexes that were rebuilt in the databases and what level of fragmentation the index was at before rebuilt. After checking these indexes, I still see that all the Primary Key indexes are still at the same fragmentation level. I run the process again and it does not change. I updated table usage and also ran update statistics after running the rebuild again, but the fragmentation does not change. Why can’t these PK Clustered indexes be rebuilt as expected? Do I need to drop and recreate the PK before this fragmentation changes?

How are you measuring the extent of the fragmentation?

Thanks

ray

|||I run sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) again to see the fragmentation. I also run DBCC SHOWCONTIG with the same results.|||

Can you please post the results of the DBCC SHOWCONTIG statement?

Thanks

Ray

|||

Results from: sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) -- Note, I added table names and Index names to the result set

TableID ,TableName, IndexID ,IndexName ,Fragmentation

87671360, [MyTable], 1 ,[MyIndex] ,83.3333333333333

Results from: DBCC SHOWCONTIG (87671360,1)

DBCC SHOWCONTIG scanning 'MyTable' table...

Table: 'MyTable' (87671360); index ID: 1, database ID: 10

TABLE level scan performed.

- Pages Scanned................................: 6

- Extents Scanned..............................: 6

- Extent Switches..............................: 5

- Avg. Pages per Extent........................: 1.0

- Scan Density [Best Count:Actual Count].......: 16.67% [1:6]

- Logical Scan Fragmentation ..................: 83.33%

- Extent Scan Fragmentation ...................: 83.33%

- Avg. Bytes Free per Page.....................: 387.8

- Avg. Page Density (full).....................: 95.21%

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

|||

Here is the code that I put in a proc but it can be run in any non sys databases. the only thing is it does create a permanent table for reporting but you can drop it any time.

SET NOCOUNT ON;

DECLARE @.v_Object_Id int;

DECLARE @.v_Index_Id int;

DECLARE @.v_Schema_Nm nvarchar(130);

DECLARE @.v_Object_Nm nvarchar(130);

DECLARE @.v_Index_Nm nvarchar(130);

DECLARE @.v_Rebuild_Stmt nvarchar(2000);

DECLARE @.v_Frag_Flt float

DECLARE @.v_Start_DtTm datetime;

DECLARE @.v_End_DtTm datetime;

DECLARE @.v_Duration_DtTm datetime;

--Uncomment if you are running the code and not the procedure

DECLARE @.ip_Frag_Limit Int

SET @.ip_Frag_Limit = 30

IF (((SELECT DB_NAME(DB_ID())) = 'master') OR ((SELECT DB_NAME(DB_ID())) = 'model') OR ((SELECT DB_NAME(DB_ID())) = 'msdb') OR ((SELECT DB_NAME(DB_ID())) = 'tempdb'))

BEGIN

PRINT 'You cannot execute this procedure in this database'

RETURN;

END

-- We want records in a permenant table so we see if it exists from a previous run

-- If it does exist, then we TRUNCATE it, otherwise, we create it

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DBA_IndexStatistics]') AND type in (N'U'))

TRUNCATE TABLE [dbo].[DBA_IndexStatistics]

ELSE

CREATE TABLE [dbo].[DBA_IndexStatistics](

[Object_Id] int NULL,

[Table_Nm] varchar(255) NULL,

[Index_Id] int NULL,

[Index_Nm] varchar(255) NULL,

[Frag] float NULL,

[IndexRebuilt_Ind] BIT NULL,

[Start_DtTm] datetime NULL,

[End_DtTm] datetime NULL,

[Duration] varchar(20) NULL

) ON [PRIMARY]

-- Load our temporary working table that will contain all of our index information

SELECT object_id AS [Object_Id], CAST('' AS sysname) AS [Table_Nm], index_id AS [Index_Id], CAST('' AS sysname) AS [Index_Nm], avg_fragmentation_in_percent AS [Frag],0 AS [IndexRebuilt_Ind], GetDate() AS [Start_DtTm], GetDate() AS [End_DtTm], '00:00:00' AS [Duration]

INTO #Tmp_Index_Stats

FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL)

WHERE Index_ID > 0

ORDER BY [Object_Id],[Index_Id];

-- Create a cursor to run through each distinct table object_id from our working table

DECLARE cur_Object CURSOR FAST_FORWARD FOR SELECT DISTINCT [Object_Id] FROM #Tmp_Index_Stats ORDER BY [Object_Id]

OPEN cur_Object

FETCH NEXT FROM cur_Object INTO @.v_Object_Id

WHILE @.@.FETCH_STATUS = 0

BEGIN

-- Check to see if the table has a Clustered index AND has any other NonClustered index with fragmentation >= the limit passed in the procedure

IF ((SELECT MIN([Index_Id]) FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id) = 1) AND ((SELECT COUNT([Object_Id]) FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id AND [Frag] >= @.ip_Frag_Limit) > 0)

BEGIN

-- If true then rebuild the Clustered Index only

SELECT @.v_Object_Nm = QUOTENAME(o.name), @.v_Schema_Nm = QUOTENAME(s.name)

FROM sys.objects AS o

JOIN sys.schemas as s ON s.schema_id = o.schema_id

WHERE o.object_id = @.v_Object_Id;

SELECT @.v_Index_Nm = QUOTENAME(name)

FROM sys.indexes

WHERE object_id = @.v_Object_Id AND Index_ID = 1;

-- Set Start time before rebuild

SET @.v_Start_DtTm = GetDate()

--SET @.v_Rebuild_Stmt = N'ALTER INDEX ALL ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

SET @.v_Rebuild_Stmt = N'ALTER INDEX ' + @.v_Index_Nm + N' ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

EXEC sp_executesql @.v_Rebuild_Stmt

--PRINT @.v_Rebuild_Stmt

-- Set End Time and Duration after rebuild

SET @.v_End_DtTm = GetDate()

SET @.v_Duration_DtTm = (@.v_End_DtTm - @.v_Start_DtTm)

-- Update values in our temp table that we will store in the permenant table.

UPDATE #Tmp_Index_Stats SET [IndexRebuilt_Ind] = 1 WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Table_Nm] = @.v_Object_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Index_Nm] = @.v_Index_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Start_DtTm] = @.v_Start_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [End_DtTm] = @.v_End_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Duration] = CONVERT(Varchar(20),@.v_Duration_DtTm,108) WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

END

ELSE

-- In this case, we do not have a Clustered index. Then we need to check each individual NonClustered index for fragmentation limits

BEGIN

-- Get a list of NonClustered indexes for this one table object_id

DECLARE cur_Index CURSOR FAST_FORWARD FOR SELECT [Index_Id], [Frag] FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id ORDER BY [Index_Id]

OPEN cur_Index

FETCH NEXT FROM cur_Index into @.v_Index_Id, @.v_Frag_Flt

WHILE @.@.FETCH_STATUS = 0

BEGIN

-- Compare actual index fragmentation to our fragmentation limit passed in to the procedure.

IF @.v_Frag_Flt >= @.ip_Frag_Limit

-- If index is more fragmented than our limit then rebuild this index

BEGIN

SELECT @.v_Object_Nm = QUOTENAME(o.name), @.v_Schema_Nm = QUOTENAME(s.name)

FROM sys.objects AS o

JOIN sys.schemas as s ON s.schema_id = o.schema_id

WHERE o.object_id = @.v_Object_Id;

SELECT @.v_Index_Nm = QUOTENAME(name)

FROM sys.indexes

WHERE object_id = @.v_Object_Id AND Index_ID = @.v_Index_Id;

-- Set Start time before rebuild

SET @.v_Start_DtTm = GetDate()

SET @.v_Rebuild_Stmt = N'ALTER INDEX ' + @.v_Index_Nm + N' ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

EXEC sp_executesql @.v_Rebuild_Stmt

--PRINT @.v_Rebuild_Stmt

-- Set End Time and Duration after rebuild

SET @.v_End_DtTm = GetDate()

SET @.v_Duration_DtTm = (@.v_End_DtTm - @.v_Start_DtTm)

-- Update values in our temp table that we will store in the permenant table.

UPDATE #Tmp_Index_Stats SET [IndexRebuilt_Ind] = 1 WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Table_Nm] = @.v_Object_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Index_Nm] = @.v_Index_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Start_DtTm] = @.v_Start_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [End_DtTm] = @.v_End_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Duration] = CONVERT(Varchar(20),@.v_Duration_DtTm,108) WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

END

FETCH NEXT FROM cur_Index into @.v_Index_Id, @.v_Frag_Flt

END

CLOSE cur_Index

DEALLOCATE cur_Index

END

FETCH NEXT FROM cur_Object into @.v_Object_Id

END

CLOSE cur_Object

DEALLOCATE cur_Object

-- Populate our permamnet table for our viewing. we only want to see what was rebuilt and how long it took.

INSERT [DBA_IndexStatistics] SELECT [Object_Id], [Table_Nm], [Index_Id], [Index_Nm], [Frag], [IndexRebuilt_Ind], [Start_DtTm], [End_DtTm], [Duration] FROM #Tmp_Index_Stats WHERE [IndexRebuilt_Ind] = 1 ORDER BY [Duration] DESC

-- Drop our temporary table

DROP TABLE #Tmp_Index_Stats

SELECT * FROM [DBA_IndexStatistics] ORDER BY [Duration] DESC

|||

One thing i would say is that in SQL2005 rebuilding a clustered index does NOT rebuild all associated nonclustered indexes.

Would that explain the behaviour you are seeing?

|||No, I realized that. If you look at the code block for the Clustered Indexes, there is a line commented out that runs the ALTER INDEX ALL ON... However, this still shows that the Primary Key Clustered Indexes retain the same fragmentation levels.

PK still shows fragmentation after ALTER INDEX.. REBUILD

I am using sys.dm_db_index_physical_stats to identify indexes that need to be rebuilt based on a fragmentation limit. Once identified, I execute and ALTER INDEX... REBUILD on the index. If the index is clustered, only that index gets rebuilt for the table. After all the indexes are complete, I receive a report on the indexes that were rebuilt in the databases and what level of fragmentation the index was at before rebuilt. After checking these indexes, I still see that all the Primary Key indexes are still at the same fragmentation level. I run the process again and it does not change. I updated table usage and also ran update statistics after running the rebuild again, but the fragmentation does not change. Why can’t these PK Clustered indexes be rebuilt as expected? Do I need to drop and recreate the PK before this fragmentation changes?

How are you measuring the extent of the fragmentation?

Thanks

ray

|||I run sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) again to see the fragmentation. I also run DBCC SHOWCONTIG with the same results.|||

Can you please post the results of the DBCC SHOWCONTIG statement?

Thanks

Ray

|||

Results from: sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) -- Note, I added table names and Index names to the result set

TableID ,TableName, IndexID ,IndexName ,Fragmentation

87671360, [MyTable], 1 ,[MyIndex] ,83.3333333333333

Results from: DBCC SHOWCONTIG (87671360,1)

DBCC SHOWCONTIG scanning 'MyTable' table...

Table: 'MyTable' (87671360); index ID: 1, database ID: 10

TABLE level scan performed.

- Pages Scanned................................: 6

- Extents Scanned..............................: 6

- Extent Switches..............................: 5

- Avg. Pages per Extent........................: 1.0

- Scan Density [Best Count:Actual Count].......: 16.67% [1:6]

- Logical Scan Fragmentation ..................: 83.33%

- Extent Scan Fragmentation ...................: 83.33%

- Avg. Bytes Free per Page.....................: 387.8

- Avg. Page Density (full).....................: 95.21%

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

|||

Here is the code that I put in a proc but it can be run in any non sys databases. the only thing is it does create a permanent table for reporting but you can drop it any time.

SET NOCOUNT ON;

DECLARE @.v_Object_Id int;

DECLARE @.v_Index_Id int;

DECLARE @.v_Schema_Nm nvarchar(130);

DECLARE @.v_Object_Nm nvarchar(130);

DECLARE @.v_Index_Nm nvarchar(130);

DECLARE @.v_Rebuild_Stmt nvarchar(2000);

DECLARE @.v_Frag_Flt float

DECLARE @.v_Start_DtTm datetime;

DECLARE @.v_End_DtTm datetime;

DECLARE @.v_Duration_DtTm datetime;

--Uncomment if you are running the code and not the procedure

DECLARE @.ip_Frag_Limit Int

SET @.ip_Frag_Limit = 30

IF (((SELECT DB_NAME(DB_ID())) = 'master') OR ((SELECT DB_NAME(DB_ID())) = 'model') OR ((SELECT DB_NAME(DB_ID())) = 'msdb') OR ((SELECT DB_NAME(DB_ID())) = 'tempdb'))

BEGIN

PRINT 'You cannot execute this procedure in this database'

RETURN;

END

-- We want records in a permenant table so we see if it exists from a previous run

-- If it does exist, then we TRUNCATE it, otherwise, we create it

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DBA_IndexStatistics]') AND type in (N'U'))

TRUNCATE TABLE [dbo].[DBA_IndexStatistics]

ELSE

CREATE TABLE [dbo].[DBA_IndexStatistics](

[Object_Id] int NULL,

[Table_Nm] varchar(255) NULL,

[Index_Id] int NULL,

[Index_Nm] varchar(255) NULL,

[Frag] float NULL,

[IndexRebuilt_Ind] BIT NULL,

[Start_DtTm] datetime NULL,

[End_DtTm] datetime NULL,

[Duration] varchar(20) NULL

) ON [PRIMARY]

-- Load our temporary working table that will contain all of our index information

SELECT object_id AS [Object_Id], CAST('' AS sysname) AS [Table_Nm], index_id AS [Index_Id], CAST('' AS sysname) AS [Index_Nm], avg_fragmentation_in_percent AS [Frag],0 AS [IndexRebuilt_Ind], GetDate() AS [Start_DtTm], GetDate() AS [End_DtTm], '00:00:00' AS [Duration]

INTO #Tmp_Index_Stats

FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL)

WHERE Index_ID > 0

ORDER BY [Object_Id],[Index_Id];

-- Create a cursor to run through each distinct table object_id from our working table

DECLARE cur_Object CURSOR FAST_FORWARD FOR SELECT DISTINCT [Object_Id] FROM #Tmp_Index_Stats ORDER BY [Object_Id]

OPEN cur_Object

FETCH NEXT FROM cur_Object INTO @.v_Object_Id

WHILE @.@.FETCH_STATUS = 0

BEGIN

-- Check to see if the table has a Clustered index AND has any other NonClustered index with fragmentation >= the limit passed in the procedure

IF ((SELECT MIN([Index_Id]) FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id) = 1) AND ((SELECT COUNT([Object_Id]) FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id AND [Frag] >= @.ip_Frag_Limit) > 0)

BEGIN

-- If true then rebuild the Clustered Index only

SELECT @.v_Object_Nm = QUOTENAME(o.name), @.v_Schema_Nm = QUOTENAME(s.name)

FROM sys.objects AS o

JOIN sys.schemas as s ON s.schema_id = o.schema_id

WHERE o.object_id = @.v_Object_Id;

SELECT @.v_Index_Nm = QUOTENAME(name)

FROM sys.indexes

WHERE object_id = @.v_Object_Id AND Index_ID = 1;

-- Set Start time before rebuild

SET @.v_Start_DtTm = GetDate()

--SET @.v_Rebuild_Stmt = N'ALTER INDEX ALL ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

SET @.v_Rebuild_Stmt = N'ALTER INDEX ' + @.v_Index_Nm + N' ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

EXEC sp_executesql @.v_Rebuild_Stmt

--PRINT @.v_Rebuild_Stmt

-- Set End Time and Duration after rebuild

SET @.v_End_DtTm = GetDate()

SET @.v_Duration_DtTm = (@.v_End_DtTm - @.v_Start_DtTm)

-- Update values in our temp table that we will store in the permenant table.

UPDATE #Tmp_Index_Stats SET [IndexRebuilt_Ind] = 1 WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Table_Nm] = @.v_Object_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Index_Nm] = @.v_Index_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Start_DtTm] = @.v_Start_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [End_DtTm] = @.v_End_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

UPDATE #Tmp_Index_Stats SET [Duration] = CONVERT(Varchar(20),@.v_Duration_DtTm,108) WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = 1

END

ELSE

-- In this case, we do not have a Clustered index. Then we need to check each individual NonClustered index for fragmentation limits

BEGIN

-- Get a list of NonClustered indexes for this one table object_id

DECLARE cur_Index CURSOR FAST_FORWARD FOR SELECT [Index_Id], [Frag] FROM #Tmp_Index_Stats WHERE [Object_Id] = @.v_Object_Id ORDER BY [Index_Id]

OPEN cur_Index

FETCH NEXT FROM cur_Index into @.v_Index_Id, @.v_Frag_Flt

WHILE @.@.FETCH_STATUS = 0

BEGIN

-- Compare actual index fragmentation to our fragmentation limit passed in to the procedure.

IF @.v_Frag_Flt >= @.ip_Frag_Limit

-- If index is more fragmented than our limit then rebuild this index

BEGIN

SELECT @.v_Object_Nm = QUOTENAME(o.name), @.v_Schema_Nm = QUOTENAME(s.name)

FROM sys.objects AS o

JOIN sys.schemas as s ON s.schema_id = o.schema_id

WHERE o.object_id = @.v_Object_Id;

SELECT @.v_Index_Nm = QUOTENAME(name)

FROM sys.indexes

WHERE object_id = @.v_Object_Id AND Index_ID = @.v_Index_Id;

-- Set Start time before rebuild

SET @.v_Start_DtTm = GetDate()

SET @.v_Rebuild_Stmt = N'ALTER INDEX ' + @.v_Index_Nm + N' ON ' + @.v_Schema_Nm + N'.' + @.v_Object_Nm + N' REBUILD WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON)';

EXEC sp_executesql @.v_Rebuild_Stmt

--PRINT @.v_Rebuild_Stmt

-- Set End Time and Duration after rebuild

SET @.v_End_DtTm = GetDate()

SET @.v_Duration_DtTm = (@.v_End_DtTm - @.v_Start_DtTm)

-- Update values in our temp table that we will store in the permenant table.

UPDATE #Tmp_Index_Stats SET [IndexRebuilt_Ind] = 1 WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Table_Nm] = @.v_Object_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Index_Nm] = @.v_Index_Nm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Start_DtTm] = @.v_Start_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [End_DtTm] = @.v_End_DtTm WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

UPDATE #Tmp_Index_Stats SET [Duration] = CONVERT(Varchar(20),@.v_Duration_DtTm,108) WHERE [Object_Id] = @.v_Object_Id AND [Index_Id] = @.v_Index_Id

END

FETCH NEXT FROM cur_Index into @.v_Index_Id, @.v_Frag_Flt

END

CLOSE cur_Index

DEALLOCATE cur_Index

END

FETCH NEXT FROM cur_Object into @.v_Object_Id

END

CLOSE cur_Object

DEALLOCATE cur_Object

-- Populate our permamnet table for our viewing. we only want to see what was rebuilt and how long it took.

INSERT [DBA_IndexStatistics] SELECT [Object_Id], [Table_Nm], [Index_Id], [Index_Nm], [Frag], [IndexRebuilt_Ind], [Start_DtTm], [End_DtTm], [Duration] FROM #Tmp_Index_Stats WHERE [IndexRebuilt_Ind] = 1 ORDER BY [Duration] DESC

-- Drop our temporary table

DROP TABLE #Tmp_Index_Stats

SELECT * FROM [DBA_IndexStatistics] ORDER BY [Duration] DESC

|||

One thing i would say is that in SQL2005 rebuilding a clustered index does NOT rebuild all associated nonclustered indexes.

Would that explain the behaviour you are seeing?

|||No, I realized that. If you look at the code block for the Clustered Indexes, there is a line commented out that runs the ALTER INDEX ALL ON... However, this still shows that the Primary Key Clustered Indexes retain the same fragmentation levels.