本文是在阅读《Troubleshooting SQL Server》->Chapter 5: Missing Indexes->Identifying Duplicate Indexes时,文中提及两个处理重复索引的链接。此处整理链接文章,方便自己后期查看,详细内容请参考原文:How can you tell if an index is REALLY a duplicate? and Removing duplicate indexes
一、创建新的存储过程,返回表上的索引信息
Step 1: Setup sp_SQLskills_ExposeColsInIndexLevels

/*============================================================================
  File:     sp_SQLskills_ExposeColsInIndexLevels

  Summary:  This procedure lists columns in the key vs. those in the leaf level
            of a nonclustered index. This is dependent on whether or not the 
            nonclustered is UNIQUE as well as whether or not the table has a 
            clustered index. It also changes based on whether or not the 
            clustering key is UNIQUE.
            
  Date:     May 2010

  Version:    SQL Server 2005/2008
------------------------------------------------------------------------------
  Written by Paul S. Randal and Kimberly L. Tripp, SQLskills.com

  For more scripts and sample code, check out 
    http://www.SQLskills.com

  This script is intended only as a supplement to demos and lectures
  given by SQLskills instructors.  
  
  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF 
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.
============================================================================*/

USE master
go

if OBJECTPROPERTY(OBJECT_ID('sp_SQLskills_ExposeColsInIndexLevels'), 'IsProcedure') = 1
    drop procedure sp_SQLskills_ExposeColsInIndexLevels
go

create procedure sp_SQLskills_ExposeColsInIndexLevels 
(
    @object_id int,
    @index_id int,
    @ColsInTree nvarchar(2126) OUTPUT,
    @ColsInLeaf nvarchar(max) OUTPUT
)
AS
BEGIN
    declare @nonclus_uniq int
            , @column_id int
            , @column_name nvarchar(260)
            , @col_descending bit
            , @colstr    nvarchar (max);

    -- Get clustered index keys (id and name)
    select sic.column_id, QUOTENAME(sc.name, N']') AS column_name, is_descending_key
    into #clus_keys 
    from sys.index_columns AS sic
        JOIN sys.columns AS sc
            ON sic.column_id = sc.column_id AND sc.object_id = sic.object_id
    where sic.[object_id] = @object_id
    and [index_id] = 1;
    
    -- Get nonclustered index keys
    select sic.column_id, sic.is_included_column, QUOTENAME(sc.name, N']') AS column_name, is_descending_key
    into #nonclus_keys 
    from sys.index_columns AS sic
        JOIN sys.columns AS sc
            ON sic.column_id = sc.column_id 
                AND sc.object_id = sic.object_id
    where sic.[object_id] = @object_id
        and sic.[index_id] = @index_id;
        
    -- Is the nonclustered unique?
    select @nonclus_uniq = is_unique 
    from sys.indexes
    where [object_id] = @object_id
        and [index_id] = @index_id;

    if (@nonclus_uniq = 0)
    begin
        -- Case 1: nonunique nonclustered index

        -- cursor for nonclus columns not included and
        -- nonclus columns included but also clus keys
        declare mycursor cursor for
            select column_id, column_name, is_descending_key  
            from #nonclus_keys
            where is_included_column = 0
        open mycursor;
        fetch next from mycursor into @column_id, @column_name, @col_descending;
        WHILE @@FETCH_STATUS = 0
        begin
            select @colstr = ISNULL(@colstr, N'') + @column_name + CASE WHEN @col_descending = 1 THEN '(-)' ELSE N'' END + N', ';
            fetch next from mycursor into @column_id, @column_name, @col_descending;
        end
        close mycursor;
        deallocate mycursor;
        
        -- cursor over clus_keys if clustered
        declare mycursor cursor for
            select column_id, column_name, is_descending_key from #clus_keys
            where column_id not in (select column_id from #nonclus_keys
                where is_included_column = 0)
        open mycursor;
        fetch next from mycursor into @column_id, @column_name, @col_descending;
        WHILE @@FETCH_STATUS = 0
        begin
            select @colstr = ISNULL(@colstr, N'') + @column_name + CASE WHEN @col_descending = 1 THEN '(-)' ELSE N'' END + N', ';
            fetch next from mycursor into @column_id, @column_name, @col_descending;
        end
        close mycursor;
        deallocate mycursor;    
        
        select @ColsInTree = substring(@colstr, 1, LEN(@colstr) -1);
            
        -- find columns not in the nc and not in cl - that are still left to be included.
        declare mycursor cursor for
            select column_id, column_name, is_descending_key from #nonclus_keys
            where column_id not in (select column_id from #clus_keys UNION select column_id from #nonclus_keys where is_included_column = 0)
        open mycursor;
        fetch next from mycursor into @column_id, @column_name, @col_descending;
        WHILE @@FETCH_STATUS = 0
        begin
            select @colstr = ISNULL(@colstr, N'') + @column_name + CASE WHEN @col_descending = 1 THEN '(-)' ELSE N'' END + N', ';
            fetch next from mycursor into @column_id, @column_name, @col_descending;
        end
        close mycursor;
        deallocate mycursor;    
        
        select @ColsInLeaf = substring(@colstr, 1, LEN(@colstr) -1);
        
    end

    -- Case 2: unique nonclustered
    else
    begin
        -- cursor over nonclus_keys that are not includes
        select @colstr = ''
        declare mycursor cursor for
            select column_id, column_name, is_descending_key from #nonclus_keys
            where is_included_column = 0
        open mycursor;
        fetch next from mycursor into @column_id, @column_name, @col_descending;
        WHILE @@FETCH_STATUS = 0
        begin
            select @colstr = ISNULL(@colstr, N'') + @column_name + CASE WHEN @col_descending = 1 THEN '(-)' ELSE N'' END + N', ';
            fetch next from mycursor into @column_id, @column_name, @col_descending;
        end
        close mycursor;
        deallocate mycursor;
        
        select @ColsInTree = substring(@colstr, 1, LEN(@colstr) -1);
    
        -- start with the @ColsInTree and add remaining columns not present...
        declare mycursor cursor for
            select column_id, column_name, is_descending_key from #nonclus_keys 
            WHERE is_included_column = 1;
        open mycursor;
        fetch next from mycursor into @column_id, @column_name, @col_descending;
        WHILE @@FETCH_STATUS = 0
        begin
            select @colstr = ISNULL(@colstr, N'') + @column_name + CASE WHEN @col_descending = 1 THEN '(-)' ELSE N'' END + N', ';
            fetch next from mycursor into @column_id, @column_name, @col_descending;
        end
        close mycursor;
        deallocate mycursor;

        -- get remaining clustered column as long as they're not already in the nonclustered
        declare mycursor cursor for
            select column_id, column_name, is_descending_key from #clus_keys
            where column_id not in (select column_id from #nonclus_keys)
        open mycursor;
        fetch next from mycursor into @column_id, @column_name, @col_descending;
        WHILE @@FETCH_STATUS = 0
        begin
            select @colstr = ISNULL(@colstr, N'') + @column_name + CASE WHEN @col_descending = 1 THEN '(-)' ELSE N'' END + N', ';
            fetch next from mycursor into @column_id, @column_name, @col_descending;
        end
        close mycursor;
        deallocate mycursor;    

        select @ColsInLeaf = substring(@colstr, 1, LEN(@colstr) -1);
        select @colstr = ''
    
    end
    -- Cleanup
    drop table #clus_keys;
    drop table #nonclus_keys;
    
END;
GO

exec sys.sp_MS_marksystemobject 'sp_SQLskills_ExposeColsInIndexLevels'
go
sp_SQLskills_ExposeColsInIndexLevels

相关文章: