根据表名和列名获取关联index的创建脚本

需求背景:

因为index的命名不规范,有时候很难判断,相关字段上有index

针对以上需求,写了以下脚本来获取相关信息


 

如果创建一个index

use [lynntest]
go
create index ix_abc on [dbo].[tb] (indate,ca)include(flag)with(fillfactor=85)

下面使用脚本获取结果

/*
desc:get table's crate index script
*/
DECLARE
@idxTableName SYSNAME,
@idxTableID INT,
@idxname SYSNAME,
@idxid INT,
@colCount INT,
@colCountMinusIncludedColumns INT,
@IxColumn SYSNAME,
@IxFirstColumn BIT,
@ColumnIDInTable INT,
@ColumnIDInIndex INT,
@IsIncludedColumn INT,
@sIncludeCols VARCHAR(MAX),
@sIndexCols VARCHAR(MAX),
@sSQL VARCHAR(MAX),
@sParamSQL VARCHAR(MAX),
@sFilterSQL VARCHAR(MAX),
@location SYSNAME,
@IndexCount INT,
@CurrentIndex INT,
@CurrentCol INT,
@Name VARCHAR(128),
@IsPrimaryKey TINYINT,
@Fillfactor INT,
@FilterDefinition VARCHAR(MAX),
@IsClustered BIT ,
@S varchar(max),
@X xml

SET @S = 'tb,ca'  --input tbname,columnname


IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = object_id(N'[tempdb].[dbo].[#TabColTab]'))
DROP TABLE [dbo].[#TabColTab]

CREATE TABLE #TabColTab
(
     TabName sysname
    ,ColName sysname
)

IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = object_id(N'[tempdb].[dbo].[#TabIdxTab]'))
DROP TABLE [dbo].[#TabIdxTab]
 


CREATE TABLE #TabIdxTab
(
     TabName sysname
    ,IndexName sysname
)


SELECT
      @S = N'<root><col>' + REPLACE(@s,CHAR(10),N'</col><col>') + N'</col></root>',
            @X = CONVERT(xml,@s)

;WITH CTE AS(
      SELECT
                        REPLACE(REPLACE(REPLACE(REPLACE(col,CHAR(10),N''),CHAR(13),N''),CHAR(9),N''),',','.') AS COL
      FROM
      (
                        SELECT 
                                          REPLACE(RTRIM(LTRIM(T.c.value(N'(text())[1]',N'nvarchar(300)'))),CHAR(10),N'') AS col
                        FROM @X.nodes('/root/col') T(c)
      )A
      WHERE A.col IS NOT NULL
)
,CTE2 AS(
      SELECT
            TabName = PARSENAME(COL,2),
            ColName = PARSENAME(COL,1)
      FROM CTE
)

INSERT INTO [#TabColTab] 
SELECT 
    * 
FROM CTE2

DECLARE @TabName1 sysname
       ,@ColName1 sysname
DECLARE Tab_Cursor CURSOR 
FOR 
SELECT 
    TabName
   ,ColName 
FROM #TabColTab

OPEN Tab_Cursor;

FETCH NEXT FROM Tab_Cursor INTO @TabName1
                                 ,@ColName1;

WHILE @@FETCH_STATUS = 0
BEGIN
    
    INSERT INTO #TabIdxTab    
    SELECT  
        OBJECT_NAME(A.OBJECT_ID)    AS TabName 
       ,A.name AS index_name  
    FROM sys.indexes A JOIN sys.index_columns B ON B.OBJECT_ID = A.OBJECT_ID AND B.index_id = A.index_id JOIN sys.columns C ON C.OBJECT_ID = B.OBJECT_ID AND C.column_id = B.column_id 
    WHERE 
        a.OBJECT_ID=OBJECT_ID(@tabname1) 
        AND c.name=@colname1
    FETCH NEXT FROM Tab_Cursor INTO @TabName1
                                     ,@ColName1;
    END
    CLOSE Tab_Cursor;
    DEALLOCATE Tab_Cursor;


IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = object_id(N'[tempdb].[dbo].[#IndexSQL]'))
DROP TABLE [dbo].[#IndexSQL]

CREATE TABLE #IndexSQL
( TableName VARCHAR(128) NOT NULL
 ,IndexName VARCHAR(128) NOT NULL
 ,IsClustered BIT NOT NULL
 ,IsPrimaryKey BIT NOT NULL
 ,IndexCreateSQL VARCHAR(max) NOT NULL
)


IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = object_id(N'[tempdb].[dbo].[#IndexListing]'))
DROP TABLE [dbo].[#IndexListing]

CREATE TABLE #IndexListing
(
[IndexListingID] INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
[TableName] SYSNAME COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[ObjectID] INT NOT NULL,
[IndexName] SYSNAME COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[IndexID] INT NOT NULL,
[IsPrimaryKey] TINYINT NOT NULL,
[FillFactor] INT,
[FilterDefinition] NVARCHAR(MAX) NULL
)

IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE id = object_id(N'[tempdb].[dbo].[#ColumnListing]'))
DROP TABLE [dbo].[#ColumnListing]

CREATE TABLE #ColumnListing
(
[ColumnListingID] INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
[ColumnIDInTable] INT NOT NULL,
[Name] SYSNAME COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[ColumnIDInIndex] INT NOT NULL,
[IsIncludedColumn] BIT NULL
)

INSERT INTO #IndexListing( [TableName], [ObjectID], [IndexName], [IndexID], [IsPrimaryKey], [FILLFACTOR], [FilterDefinition] )
SELECT OBJECT_NAME(si.object_id), si.object_id, si.name, si.index_id, si.Is_Primary_Key, si.Fill_Factor, si.filter_definition
FROM sys.indexes si
LEFT OUTER JOIN information_schema.table_constraints tc ON si.name = tc.constraint_name AND OBJECT_NAME(si.object_id) = tc.table_name
WHERE OBJECTPROPERTY(si.object_id, 'IsUserTable') = 1
ORDER BY OBJECT_NAME(si.object_id), si.index_id

SELECT @IndexCount = @@ROWCOUNT, @CurrentIndex = 1

WHILE @CurrentIndex <= @IndexCount
BEGIN

    SELECT @idxTableName = [TableName],
    @idxTableID = [ObjectID],
    @idxname = [IndexName],
    @idxid = [IndexID],
    @IsPrimaryKey = [IsPrimaryKey],
    @FillFactor = [FILLFACTOR],
    @FilterDefinition = [FilterDefinition]
    FROM #IndexListing
    WHERE [IndexListingID] = @CurrentIndex

    -- So - it is either an index or a constraint
    -- Check if the index is unique
    IF (@IsPrimaryKey = 1)
    BEGIN
     SET @sSQL = 'ALTER TABLE [dbo].[' + @idxTableName + '] ADD CONSTRAINT [' + @idxname + '] PRIMARY KEY '
     -- Check if the index is clustered
     IF (INDEXPROPERTY(@idxTableID, @idxname, 'IsClustered') = 0)
     BEGIN
     SET @sSQL = @sSQL + 'NON'
     SET @IsClustered = 0
     END
     ELSE
     BEGIN
     SET @IsClustered = 1
     END
     SET @sSQL = @sSQL + 'CLUSTERED' + CHAR(13) + '(' + CHAR(13)
    END
    ELSE
    BEGIN
     SET @sSQL = 'CREATE '
     -- Check if the index is unique
     IF (INDEXPROPERTY(@idxTableID, @idxname, 'IsUnique') = 1)
     BEGIN
     SET @sSQL = @sSQL + 'UNIQUE '
     END
     -- Check if the index is clustered
     IF (INDEXPROPERTY(@idxTableID, @idxname, 'IsClustered') = 1)
     BEGIN
     SET @sSQL = @sSQL + 'CLUSTERED '
     SET @IsClustered = 1
     END
     ELSE
     BEGIN
     SET @IsClustered = 0
     END

     SELECT
     @sSQL = @sSQL + 'INDEX [' + @idxname + '] ON [dbo].[' + @idxTableName + ']' + CHAR(13) + '(' + CHAR(13),
     @colCount = 0,
     @colCountMinusIncludedColumns = 0
    END

    -- Get the nuthe mber of cols in the index
    SELECT @colCount = COUNT(*),
           @colCountMinusIncludedColumns = SUM(CASE ic.is_included_column WHEN 0 THEN 1 ELSE 0 END)
    FROM sys.index_columns ic
    INNER JOIN sys.columns sc ON ic.object_id = sc.object_id AND ic.column_id = sc.column_id
    WHERE ic.object_id = @idxtableid AND index_id = @idxid

    -- Get the file group info
    SELECT @location = f.[name]
    FROM sys.indexes i
    INNER JOIN sys.filegroups f ON i.data_space_id = f.data_space_id
    INNER JOIN sys.all_objects o ON i.[object_id] = o.[object_id]
    WHERE o.object_id = @idxTableID AND i.index_id = @idxid

    -- Get all columns of the index
    INSERT INTO #ColumnListing( [ColumnIDInTable], [Name], [ColumnIDInIndex],[IsIncludedColumn] )
    SELECT sc.column_id, sc.name, ic.index_column_id, ic.is_included_column
    FROM sys.index_columns ic
    INNER JOIN sys.columns sc ON ic.object_id = sc.object_id AND ic.column_id = sc.column_id
    WHERE ic.object_id = @idxTableID AND index_id = @idxid
    ORDER BY ic.index_column_id

    IF @@ROWCOUNT > 0
    BEGIN

    SELECT @CurrentCol = 1
    SELECT @IxFirstColumn = 1, @sIncludeCols = '', @sIndexCols = ''
    
    WHILE @CurrentCol <= @ColCount
    BEGIN
        SELECT @ColumnIDInTable = ColumnIDInTable,
        @Name = Name,
        @ColumnIDInIndex = ColumnIDInIndex,
        @IsIncludedColumn = IsIncludedColumn
        FROM #ColumnListing
        WHERE [ColumnListingID] = @CurrentCol

        IF @IsIncludedColumn = 0
        BEGIN

            SELECT @sIndexCols = CHAR(9) + @sIndexCols + '[' + @Name + '] '

            IF (INDEXKEY_PROPERTY (@idxTableID,@idxid,@ColumnIDInIndex,'IsDescending')) = 0
                BEGIN
                SET @sIndexCols = @sIndexCols + ' ASC '
                END
            ELSE
                BEGIN
                SET @sIndexCols = @sIndexCols + ' DESC '
                END

            IF @CurrentCol < @colCountMinusIncludedColumns
                BEGIN
                SET @sIndexCols = @sIndexCols + ', '
                END

        END
        ELSE
        BEGIN
            -- Check for any include columns
            IF LEN(@sIncludeCols) > 0
                BEGIN
                SET @sIncludeCols = @sIncludeCols + ','
                END

            SELECT @sIncludeCols = @sIncludeCols + '[' + @Name + ']'

        END

            SET @CurrentCol = @CurrentCol + 1
    END

    TRUNCATE TABLE #ColumnListing
    --append to the result
    IF LEN(@sIncludeCols) > 0
        SET @sIndexCols = @sSQL + @sIndexCols + CHAR(13) + ') ' + ' INCLUDE ( ' + @sIncludeCols + ' ) '
    ELSE
        SET @sIndexCols = @sSQL + @sIndexCols + CHAR(13) + ') '

    -- Add filtering
    IF @FilterDefinition IS NOT NULL
        SET @sFilterSQL = ' WHERE ' + @FilterDefinition + ' ' + CHAR(13)
    ELSE
        SET @sFilterSQL = ''

    -- Build the options
    SET @sParamSQL = ''


    -- Fillfactor 0 is actually not a valid percentage on SQL 2008 R2
    IF ISNULL( @FillFactor, 90 ) <> 0 
     SET @sParamSQL = @sParamSQL + ' WITH (FILLFACTOR = ' + CAST( ISNULL( @FillFactor, 90 ) AS VARCHAR(3) ) +')'




    SET @sSQL = @sIndexCols + CHAR(13) + @sFilterSQL + CHAR(13) + @sParamSQL  

    -- 2008 R2 allows ON [filegroup] for primary keys as well, negating the old "IF THE INDEX IS NOT A PRIMARY KEY - ADD THIS - ELSE DO NOT" IsPrimaryKey IF statement
    SET @sSQL = @sSQL + ' ON [' + @location + ']'

    --PRINT @sIndexCols + CHAR(13)
    INSERT INTO #IndexSQL (TableName, IndexName, IsClustered, IsPrimaryKey, IndexCreateSQL) VALUES (@idxTableName, @idxName, @IsClustered, @IsPrimaryKey, @sSQL)

    END

    SET @CurrentIndex = @CurrentIndex + 1
END




SELECT a.* FROM #IndexSQL as a inner join #TabIdxTab as b on a.TableName=b.tabname and a.indexname=b.indexname
 
View Code

结果如图


CREATE INDEX [ix_abc] ON [dbo].[tb] ( [indate] ASC , [ca] ASC ) INCLUDE ( [flag] ) WITH (FILLFACTOR = 85) ON [PRIMARY]

 

note:当然可以使用 alt+f1实现

posted @ 2016-08-17 18:13  simplelg17  阅读(262)  评论(0编辑  收藏  举报