Rebuild or reorganize indexes

  • Hi

    I tried to rebuild/reogranize indexes based on the help available in BOL: ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.en/tsqlref9/html/d294dd8e-82d5-4628-aa2d-e57702230613.htm.

    First of all, it throws error for DB_ID().

    Later after providing the DB_ID number I executed the script. But when I run the SELECT part alone, it shows the same list.

    The code goes below:

    The following example automatically reorganizes or rebuilds all partitions in a database that have an average fragmentation over 10 percent. Executing this query requires the VIEW DATABASE STATE permission

    ensure a USE statement has been executed first.

    SET NOCOUNT ON;

    DECLARE @objectid int;

    DECLARE @indexid int;

    DECLARE @partitioncount bigint;

    DECLARE @schemaname sysname;

    DECLARE @objectname sysname;

    DECLARE @indexname sysname;

    DECLARE @partitionnum bigint;

    DECLARE @partitions bigint;

    DECLARE @frag float;

    DECLARE @command varchar(8000);

    -- ensure the temporary table does not exist

    IF EXISTS (SELECT name FROM sys.objects WHERE name = 'work_to_do')

    DROP TABLE work_to_do;

    -- conditionally select from the function, converting object and index IDs to names.

    SELECT

    object_id AS objectid,

    index_id AS indexid,

    partition_number AS partitionnum,

    avg_fragmentation_in_percent AS frag

    INTO work_to_do

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

    WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;

    -- Declare the cursor for the list of partitions to be processed.

    DECLARE partitions CURSOR FOR SELECT * FROM work_to_do;

    -- Open the cursor.

    OPEN partitions;

    -- Loop through the partitions.

    FETCH NEXT

    FROM partitions

    INTO @objectid, @indexid, @partitionnum, @frag;

    WHILE @@FETCH_STATUS = 0

    BEGIN;

    SELECT @objectname = o.name, @schemaname = s.name

    FROM sys.objects AS o

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

    WHERE o.object_id = @objectid;

    SELECT @indexname = name

    FROM sys.indexes

    WHERE object_id = @objectid AND index_id = @indexid;

    SELECT @partitioncount = count (*)

    FROM sys.partitions

    WHERE object_id = @objectid AND index_id = @indexid;

    -- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding

    IF @frag < 30.0
    BEGIN;
    SELECT @command = 'ALTER INDEX ' + @indexname + ' ON ' + @schemaname + '.' + @objectname + ' REORGANIZE';
    IF @partitioncount > 1

    SELECT @command = @command + ' PARTITION=' + CONVERT (CHAR, @partitionnum);

    EXEC (@command);

    END;

    IF @frag >= 30.0

    BEGIN;

    SELECT @command = 'ALTER INDEX ' + @indexname +' ON ' + @schemaname + '.' + @objectname + ' REBUILD';

    IF @partitioncount > 1

    SELECT @command = @command + ' PARTITION=' + CONVERT (CHAR, @partitionnum);

    EXEC (@command);

    END;

    PRINT 'Executed ' + @command;

    FETCH NEXT FROM partitions INTO @objectid, @indexid, @partitionnum, @frag;

    END;

    -- Close and deallocate the cursor.

    CLOSE partitions;

    DEALLOCATE partitions;

    -- drop the temporary table

    IF EXISTS (SELECT name FROM sys.objects WHERE name = 'work_to_do')

    DROP TABLE work_to_do;

    GO

    Can anyone let me know what is going wrong?

    Regards

    Mohan Kumar VS

  • Mohan Kumar (9/8/2009)


    ensure a USE statement has been executed first.

    I think that's your problem. Before running the rest of the script you need to change your database context because DB_ID() without a parameter returns the current database.

    Whenever anyone has a question like this I always point them to Michelle Ufford's blog and excellent Index Defrag Script[/url].

  • Thanks for your response. But I tried after selecting the required database.

    Anyways, I will try the script which you have mentioned also & inform you.

    Rgds

    Mohan Kumar VS

  • Let me know how you get on, as I tried your script and it didnt work for me either

    --------------------------------------------------------------------------------------
    [highlight]Recommended Articles on How to help us help you and[/highlight]
    [highlight]solve commonly asked questions[/highlight]

    Forum Etiquette: How to post data/code on a forum to get the best help by Jeff Moden[/url]
    Managing Transaction Logs by Gail Shaw[/url]
    How to post Performance problems by Gail Shaw[/url]
    Help, my database is corrupt. Now what? by Gail Shaw[/url]

  • I tried the script. But it is not completely eliminating the fragmentation. Upto 90% of fragmentation is removed.

    Thanks again.

    Regards

    Mohan Kumar VS

  • You need to check the page_count for the indexes that are not being defragmented. If they only have a few pages the fragmentation will not be removed.

  • Just to expand slightly on Jack's (very patient) comments:

    One reason that fragmentation might not be fully removed is because the first 8 data pages for an object come from 'mixed extents' (unless you set a trace flag, but I digress). Mixed extents are groups of 8 pages, where each page can belong to a different object. This is an optimization, partly so that very small objects don't require a full 64KB extent.

    Until the object reaches 25 data pages in size, a clustered index rebuild will leave the mixed extents alone (the pages allocated from these mixed extents are overwhelmingly likely to be logically fragmented). This is by design.

    When the object reaches 25 pages, a clustered index rebuild can consolidate the data pages into uniform extents (where all 8 pages belong to the same object). Higher levels of the index are subject to the same 25-page rule also, so mixed extent allocations may remain there.

    Please don't obsess about fragmentation though - unless you know that you are range-scanning large tables/indexes. These will generally benefit from being defragmented. For tables which are accessed primarily with a seek to one or a small number of rows, fragmentation is generally not at all important.

    Paul

  • Thanks Jack & Paul.

  • I executed the script twice. There are some indexes still with 40-55% fragmentation and page_count ranging from 9-151.

    Eg.

    tbl1 Frag 38.88 PageCount18

    tbl2 Frag 11.11PageCount9

    tbl3 Frag 7.01 PageCount57

    tbl4 Frag 5.30PageCount151

    IndexID is 1 for all.

    Can you please let me know what can be done for this?

    Rgds

    Mohan Kumar VS

  • Mohan Kumar (9/9/2009)


    I executed the script twice. There are some indexes still with 40-55% fragmentation and page_count ranging from 9-151.

    Eg.

    tbl1 Frag 38.88 PageCount18

    tbl2 Frag 11.11PageCount9

    tbl3 Frag 7.01 PageCount57

    tbl4 Frag 5.30PageCount151

    IndexID is 1 for all.

    Can you please let me know what can be done for this?

    Rgds

    Mohan Kumar VS

    If I recall, SQL Server may choose to bypass defragmenting if page count is less than about 1000, which is kind of a rule of thumb. Basically, at that page count or less, an index doesn't optimize selects much and treats the table the same way as if there was no index on it all. The costs of an index with that few pages are greater than a straightforward tablescan.

    I wouldn't worry too much about anything fragmented lower than a 1000 pages. So when checking for fragmentation, filter out anything with less than that threshhold number of pages.

    Gaby________________________________________________________________"In theory, theory and practice are the same. In practice, they are not." - Albert Einstein

  • Please see my previous post for details. Also:

    Make sure you are doing a REBUILD rather than a REORGANIZE.

    REORGANIZE just shuffles stuff around inside already-allocated pages - it does not allocate new pages.

    To get the most comprehensive defragmentation specify REBUILD WITH (ONLINE = OFF, SORT_IN_TEMPDB = ON).

    Paul

  • Thank you very much.

Viewing 12 posts - 1 through 11 (of 11 total)

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