Conditional Index Rebuild

  • Hi All,

    Im trying to write a script to rebuild indexes who's average fragmentation has risen above 30%. I just cannot get it to work. There are no errors created it just doesnt work. My Code is as follows:

    USE MyDatabase

    GO

    SET NOCOUNT ON

    DECLARE @TableName NVARCHAR(128)

    DECLARE @IndexName NVARCHAR(128)

    DECLARE @cmd NVARCHAR(500)

    DECLARE cIndexes CURSOR FAST_FORWARD

    FOR SELECT OBJECT_NAME(a.object_id) as TableName, name AS IndexName

    FROM sys.dm_db_index_physical_stats (DB_ID(N'MyDatabase'),

    NULL, NULL, NULL, NULL) AS a

    JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id

    WHERE avg_fragmentation_in_percent > 30.0 AND a.index_id >= 1

    OPEN cIndexes

    FETCH NEXT FROM cIndexes INTO @TableName, @IndexName

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SET @cmd = 'ALTER INDEX ['+@IndexName+'] ON [dbo].'+@TableName+'] REBUILD

    WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,

    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, SORT_IN_TEMPDB = ON,

    ONLINE = OFF )'

    EXEC (@cmd)

    FETCH NEXT FROM cIndexes INTO @TableName, @IndexName

    END

    close cIndexes

    deallocate cIndexes

    GO

    Does anyone have any thoughts? I usually manage to figure these things out only this time I'm stumped.....

  • see if this solves your purpose:

    sp_msforeachdb @command1 = 'USE [?]; select ''ALTER INDEX ''+ss.name+ '' ON ''+ object_name(si.object_id,si.database_id)+'' REBUILD ;'', db_name(si.database_id),

    ss.name,si.avg_fragmentation_in_percent

    from sys.dm_db_index_physical_stats (DB_id(),NULL,NULL,NULL,NULL) si

    join sys.indexes ss on si.object_id=ss.object_id and si.index_id=ss.index_id

    where si.database_id>4 and si.avg_fragmentation_in_percent> 30 and si.index_id>=1 '

    Just copy and paste the first part from results and Execute.

  • Thanks for the suggestion but I only want to rebuild the indexes in one specific database. Is there any reason why my code wont work?

  • A good way to check the correctness of a SQL string before executing it, is top PRINT it. You will notice that you are missing an opening bracket before @TableName

    SET @cmd = 'ALTER INDEX ['+@IndexName+'] ON [dbo].['+@TableName+'] REBUILD

    That should do the trick.

    Edit: Apparently I can't use the [ b ] tag inside a [ code ] tag.

    --
    Frank Kalis
    Microsoft SQL Server MVP
    Webmaster: http://www.insidesql.org/blogs
    My blog: http://www.insidesql.org/blogs/frankkalis/[/url]

  • I had a similar issue with a script that checks frag and rebuilds.

    Depending on how the index was created, or if it is a on a computed column you may need to force "set quoted_identifier on".

    Run your script on my DB and looks to work fine.

    Just a thought!

    JL

  • Thanks for the tip. However, I printed the string and there were no errors:

    ALTER INDEX [TestIndex] ON [dbo].[TestTable] REBUILD

    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,

    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, SORT_IN_TEMPDB = ON,

    ONLINE = OFF)

    Excuse my stupidity but I still cant see where Im missing the bracket.

  • Just seen your post sql_lock. Ill give it a try.

  • Nope, still doesnt work. Im banging my head here.

  • What is the error that is returned?

    If you try running one of the statements on its own does it work?

  • This line is in your script:

    SET @cmd = 'ALTER INDEX ['+@IndexName+'] ON [dbo].'+@TableName+'] REBUILD

    Fill that with life:

    DECLARE @cmd varchar(200), @indexname varchar(200), @tablename varchar(200)

    SELECT @indexname = '', @tablename = ''

    SET @cmd = 'ALTER INDEX ['+@IndexName+'] ON [dbo].'+@TableName+'] REBUILD'

    PRINT @cmd

    gives

    ALTER INDEX [] ON [dbo].] REBUILD

    which is not right, methinks.

    --
    Frank Kalis
    Microsoft SQL Server MVP
    Webmaster: http://www.insidesql.org/blogs
    My blog: http://www.insidesql.org/blogs/frankkalis/[/url]

  • There is no error returned. I added a print statement to the cursor and the indexes and tables are all correct.

    Just tried the rebuild statement on its own sometimes it works and others it doesnt. I have no idea whats going wrong. It must be something fundamental.

  • Apologies Frank, this was an error on my part when I first added the script. I changed it and it still doesnt work.:ermm:

  • Following up on my previous thread:

    you can restrict the query by database_id = with out the sp_msforeachdb query will look like this:

    select 'ALTER INDEX '+ss.name+ ' ON '+ object_name(si.object_id,si.database_id)+' REBUILD ;', db_name(si.database_id),

    ss.name,si.avg_fragmentation_in_percent

    from sys.dm_db_index_physical_stats (NULL,NULL,NULL,NULL,NULL) si

    join sys.indexes ss on si.object_id=ss.object_id and si.index_id=ss.index_id

    where si.database_id = 23

    and si.avg_fragmentation_in_percent> 30 and si.index_id>=1

    -- you can even use the database_id here sys.dm_db_index_physical_stats (,NULL,NULL,NULL,NULL) without the where clause for database_id

  • Regarding your script:

    Try to change the Database contect to the database you are trying to run the script in.

    use then run your cursor.

    Because the sys.indexes might be relating to the database sysindexes that you are running under and hopefully it is the master database...

    So the solution is to change to use your database then execute your script...

    See if this Helps/Works.

  • Hi

    Pls look into the BOLD area which was newly added. Now your script will generate and execute the ALTER scripts...

    USE MyDatabase

    DECLARE @TableName NVARCHAR(128)

    DECLARE @IndexName NVARCHAR(128)

    DECLARE @cmd NVARCHAR(500)

    DECLARE @DB_IDINT

    SELECT @DB_ID = DB_ID()

    DECLARE cIndexes CURSOR FAST_FORWARD

    FOR SELECT OBJECT_NAME(a.object_id) as TableName, name AS IndexName

    FROM sys.dm_db_index_physical_stats(@DB_ID,NULL, NULL, NULL, NULL) AS a

    JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id

    WHERE avg_fragmentation_in_percent > 30.0 AND a.index_id >= 1

    OPEN cIndexes

    FETCH NEXT FROM cIndexes INTO @TableName, @IndexName

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SET @cmd = 'ALTER INDEX ['+@IndexName+'] ON [dbo].'+@TableName+'] REBUILD

    WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,

    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, SORT_IN_TEMPDB = ON,

    ONLINE = OFF )'

    EXEC (@cmd)

    FETCH NEXT FROM cIndexes INTO @TableName, @IndexName

    END

    close cIndexes

    deallocate cIndexes

    Alternate wat to REBUILD / REORGANIZE :

    SP_MsForEachTable 'DBCC DBReIndex(''?'')'

    Regards

Viewing 15 posts - 1 through 15 (of 15 total)

You must be logged in to reply to this topic. Login to reply