Question

I have a maintenance task that's failing because there are a few indexes on the database that have a type which does not allow online rebuilding of the index. Offline is not an option in my industry, so I have to create my own T-SQL task that does the index rebuilding on specific indexes. The database is large with many tables and indexes, so is there a way to query the system for all indexes and their data types?

Was it helpful?

Solution

This will show you all the columns for all indices, including the columns of 'base tables' like heaps and clustered index and all INCLUDE columns as well:

select o.name as [object_name],
    ix.name as [index_name],
    coalesce(c.name,cc.name) as [column_name],
    t.name as [type_name],
    coalesce(c.max_length, cc.max_length) as max_length
from sys.indexes ix
join sys.objects o
    on ix.object_id = o.object_id
left join sys.index_columns ic
    on ix.object_id = ic.object_id
    and ix.index_id = ix.index_id
    and ix.index_id > 1
left join sys.columns c
    on  ic.object_id = c.object_id
    and ic.column_id = c.column_id
left join sys.columns cc
    on ix.object_id = cc.object_id
    and ix.index_id in (1,0)
join sys.types t
    on t.system_type_id = coalesce(c.system_type_id,cc.system_type_id)  
where o.type = 'U'
order by object_name, index_name, column_name;

You can then identify the ones unsafe for online index rebuild (the BLOB/XML/CLR types). Note that in SQL server 2012 the restriction on online index build with LOB columns was lifted, see Online Index Operations for indexes containing LOB columns.

OTHER TIPS

we've made recently such procedure. it has "HasBlobs" flag for this purpose


ALTER PROCEDURE sp_rebuild_local_idexes
@RebuildClustered bit = 0
AS
BEGIN
    DECLARE @objectid int
    DECLARE @indexid int
    DECLARE @schemaname nvarchar(130)
    DECLARE @objectname nvarchar(130)
    DECLARE @indexname nvarchar(130)
    DECLARE @partitions bigint
    DECLARE @frag float
    DECLARE @command nvarchar(4000)
    DECLARE @HasBlobs bit
    DECLARE @index_type_desc nvarchar(255)

    -- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
    -- and convert object and index IDs to names.

    SELECT
    --object_name(object_id),
    object_id AS objectid,
    index_id AS indexid,
    avg_fragmentation_in_percent AS frag,
    CASE WHEN (
        SELECT st.object_id
            from sys.tables st
            inner join sys.columns sc
                on st.object_id=sc.object_id
            inner join sys.types styp
                on sc.system_type_id=styp.system_type_id and sc.max_length=styp.max_length
            inner join sys.schemas ss
                on st.schema_id=ss.schema_id
            where styp.schema_id=4
                    and styp.name<>'sysname'
                    and styp.name IN ('xml','nvarchar','varchar','image','text','ntext')
                    AND st.object_id = a.object_id
            group by st.object_id
    )  IS NULL THEN 0 ELSE 1 END AS HasBlobs,
    a.index_type_desc
    INTO #work_to_do
    FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') AS a
    WHERE avg_fragmentation_in_percent >= 5.0 AND index_id > 0
              AND a.index_type_desc IN ('CLUSTERED INDEX','NONCLUSTERED INDEX')           
    ORDER BY a.index_type_desc

    -- Declare the cursor for the list of partitions to be processed.
    DECLARE partitions CURSOR FOR SELECT objectid,
            indexid,
            frag,
            HasBlobs,
            index_type_desc from #work_to_do
select * from #work_to_do
    -- Open the cursor.
    OPEN partitions

    -- Loop through the partitions.
    WHILE (1=1)
    BEGIN
        FETCH NEXT FROM partitions
        INTO @objectid, @indexid, @frag,@HasBlobs,@index_type_desc

        IF @@FETCH_STATUS < 0 BREAK

        IF @RebuildClustered = 1 AND @index_type_desc != 'CLUSTERED INDEX'
            CONTINUE;

        SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(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 = QUOTENAME(name)
        FROM sys.indexes
        WHERE object_id = @objectid AND index_id = @indexid and type!=3

        -- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
        IF @frag < 30.0
            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE'

        IF @frag >= 30.0
        BEGIN
            print @indexname+ @schemaname+@objectname
            SET @command = N'ALTER INDEX ' + @indexname +
                            N' ON ' +
                            @schemaname +
                            N'.' + @objectname +
                            N' REBUILD' +
                            CASE WHEN @HasBlobs = 0 THEN ' WITH(ONLINE=ON)' ELSE '' END
            print @command
        END

        EXEC (@command)
        PRINT N'Executed: ' + @command


    END

    -- Close and deallocate the cursor.
    CLOSE partitions
    DEALLOCATE partitions
END

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top