为索引列表生成 CREATE 脚本

问题描述 投票:0回答:5

作为排序规则更改练习的一部分,我有一个索引列表 (122) 需要删除然后重新创建。如何重新创建这些索引,而不必每次都通过 GUI 并将其编写脚本到查询窗口?

我的索引列表是从这个脚本获得的

WITH indexCTE AS
    (   
    SELECT Table_Name, Column_Name, Collation_Name 
    FROM information_schema.columns 
    WHERE Collation_Name IS NOT NULL AND Collation_Name = 'Modern_Spanish_CI_AS'
    ), 
    indexCTE2 AS
    (
    SELECT i.Name [Index Name], OBJECT_NAME(i.object_ID) [Table Name], c.Name [Column Name]
    FROM sys.indexes i 
    INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id
    INNER JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.OBJECT_ID
    WHERE EXISTS (SELECT 1 FROM indexCTE t1 WHERE t1.Table_Name = OBJECT_NAME(i.object_ID) AND t1.Column_Name = c.Name)
    ) SELECT * FROM indexCTE2

正如您可能知道的那样,我仍然是一名初级 DBA,所以请耐心等待!

谢谢!

sql sql-server-2005
5个回答
11
投票

我想说,你已经很接近了 - 我尝试过这个,你能验证一下这是否适合你,并向你显示预期要重新创建的 122 个索引吗??

更新:添加了确定 CLUSTERED 与 NONCLUSTERED 索引类型的功能,以及将 INCLUDEd 列添加到索引定义中。

WITH indexCTE AS
(
    SELECT DISTINCT 
        i.index_id, i.name, i.object_id
    FROM 
        sys.indexes i 
    INNER JOIN
        sys.index_columns ic 
           ON i.index_id = ic.index_id AND i.object_id = ic.object_id
    WHERE 
        EXISTS (SELECT * FROM sys.columns c 
                 WHERE c.collation_name = 'Modern_Spanish_CI_AS' 
                 AND c.column_id = ic.column_id AND c.object_id = ic.object_id)
), 
indexCTE2 AS
(
    SELECT 
        indexCTE.name 'IndexName', 
        OBJECT_NAME(indexCTE.object_ID) 'TableName',
        CASE indexCTE.index_id 
          WHEN 1 THEN 'CLUSTERED'
          ELSE 'NONCLUSTERED'
        END AS 'IndexType', 
        (SELECT DISTINCT c.name + ','
         FROM 
            sys.columns c 
         INNER JOIN
            sys.index_columns ic 
               ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0
         WHERE
            indexCTE.OBJECT_ID = ic.object_id 
            AND indexCTE.index_id = ic.index_id 
         FOR XML PATH('')
        ) ixcols,
        ISNULL(
        (SELECT DISTINCT c.name + ','
         FROM 
            sys.columns c 
         INNER JOIN
            sys.index_columns ic 
               ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1
         WHERE
            indexCTE.OBJECT_ID = ic.object_id 
            AND indexCTE.index_id = ic.index_id 
         FOR XML PATH('')
        ), '') includedcols
    FROM 
        indexCTE
) 
SELECT 
    'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + TableName + 
        '(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) + 
        CASE LEN(includedcols)
          WHEN 0 THEN ')'
          ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')'
        END
FROM 
   indexCTE2
ORDER BY 
   TableName, IndexName

您得到您正在寻找的

CREATE INDEX
陈述吗??

马克


5
投票

很棒的剧本,马克。 我认为它唯一缺少的是每列上的升序或降序指示器。我修改了您的脚本,以包含索引列的 case 语句,以根据 sys.index_columns 视图的 is_descending_key 列在 ASC 或 DESC 中添加。

WITH indexCTE AS
(
    SELECT DISTINCT 
        i.index_id, i.name, i.object_id
    FROM 
        sys.indexes i 
    INNER JOIN
        sys.index_columns ic 
           ON i.index_id = ic.index_id AND i.object_id = ic.object_id
    WHERE 
        EXISTS (SELECT * FROM sys.columns c 
                 WHERE 
                 c.collation_name = 'Modern_Spanish_CI_AS' 
                 AND c.column_id = ic.column_id AND c.object_id = ic.object_id)
), 
indexCTE2 AS
(
    SELECT 
        indexCTE.name 'IndexName', 
        OBJECT_NAME(indexCTE.object_ID) 'TableName',
        CASE indexCTE.index_id 
          WHEN 1 THEN 'CLUSTERED'
          ELSE 'NONCLUSTERED'
        END AS 'IndexType', 
        (SELECT CASE WHEN ic.is_descending_key = 1 THEN c.name + ' DESC ,'
                ELSE c.name + ' ASC ,'
                END 
         FROM 
            sys.columns c 
         INNER JOIN
            sys.index_columns ic 
               ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0
         WHERE
            indexCTE.OBJECT_ID = ic.object_id 
            AND indexCTE.index_id = ic.index_id 
         FOR XML PATH('')
        ) ixcols,
        ISNULL(
        (SELECT DISTINCT c.name + ','
         FROM 
            sys.columns c 
         INNER JOIN
            sys.index_columns ic 
               ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1
         WHERE
            indexCTE.OBJECT_ID = ic.object_id 
            AND indexCTE.index_id = ic.index_id 
         FOR XML PATH('')
        ), '') includedcols
    FROM 
        indexCTE
) 
SELECT 
    'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + TableName + 
        '(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) + 
        CASE LEN(includedcols)
          WHEN 0 THEN ')'
          ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')'
        END
FROM 
   indexCTE2
ORDER BY 
   TableName, IndexName

2
投票

TechNet有相对完整的解决方案。

SQL

SELECT ' CREATE ' +    
    CASE WHEN  I.is_unique = 1 THEN ' UNIQUE '  ELSE ''  END  +    
    I.type_desc COLLATE  DATABASE_DEFAULT +' INDEX '  +     
    I.name  + ' ON '   +    
    Schema_name(T.Schema_id)+'.'+T.name + ' ( '  +   
    KeyColumns + ' )  ' +    
    ISNULL(' INCLUDE ('+IncludedColumns+' ) ','') +   
    ISNULL(' WHERE  '+I.Filter_definition,'') + ' WITH ( '  +   
    CASE WHEN  I.is_padded = 1 THEN ' PAD_INDEX = ON '  ELSE ' PAD_INDEX = OFF '  END + ','  +   
    'FILLFACTOR = '+CONVERT(CHAR(5),CASE WHEN  I.Fill_factor = 0 THEN 100 ELSE I.Fill_factor END) + ','  +    
    -- default value   
    'SORT_IN_TEMPDB = OFF '  + ','   +   
    CASE WHEN  I.ignore_dup_key = 1 THEN ' IGNORE_DUP_KEY = ON '  ELSE ' IGNORE_DUP_KEY = OFF '  END + ','  +   
    CASE WHEN  ST.no_recompute = 0 THEN ' STATISTICS_NORECOMPUTE = OFF '  ELSE ' STATISTICS_NORECOMPUTE = ON '  END + ','  +   
    -- default value    
    ' DROP_EXISTING = ON '  + ','   +   
    -- default value    
    ' ONLINE = OFF '  + ','   +   
   CASE WHEN  I.allow_row_locks = 1 THEN ' ALLOW_ROW_LOCKS = ON '  ELSE ' ALLOW_ROW_LOCKS = OFF '  END + ','  +   
   CASE WHEN  I.allow_page_locks = 1 THEN ' ALLOW_PAGE_LOCKS = ON '  ELSE ' ALLOW_PAGE_LOCKS = OFF '  END  + ' ) ON [' +   
   DS.name + ' ] '   [CreateIndexScript]   
FROM sys.indexes I     
 JOIN sys.tables T ON T.Object_id = I.Object_id      
 JOIN sys.sysindexes SI ON I.Object_id = SI.id AND I.index_id = SI.indid     
 JOIN (SELECT * FROM (    
    SELECT IC2.object_id , IC2.index_id ,    
        STUFF((SELECT ' , ' + C.name + CASE WHEN  MAX(CONVERT(INT,IC1.is_descending_key)) = 1 THEN  ' DESC ' ELSE  ' ASC ' END 
    FROM sys.index_columns IC1    
    JOIN Sys.columns C     
       ON C.object_id = IC1.object_id     
       AND C.column_id = IC1.column_id     
       AND IC1.is_included_column = 0    
    WHERE IC1.object_id = IC2.object_id     
       AND IC1.index_id = IC2.index_id     
    GROUP BY  IC1.object_id,C.name,index_id    
    ORDER BY  MAX(IC1.key_ordinal)    
       FOR XML PATH('')), 1, 2, '') KeyColumns     
    FROM sys.index_columns IC2     
    --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables    
    GROUP BY  IC2.object_id ,IC2.index_id) tmp3 )tmp4     
  ON I.object_id = tmp4.object_id AND I.Index_id = tmp4.index_id    
 JOIN sys.stats ST ON ST.object_id = I.object_id AND ST.stats_id = I.index_id     
 JOIN sys.data_spaces DS ON I.data_space_id=DS.data_space_id     
 JOIN sys.filegroups FG ON I.data_space_id=FG.data_space_id     
 LEFT JOIN (SELECT * FROM (     
    SELECT IC2.object_id , IC2.index_id ,     
        STUFF((SELECT ' , ' + C.name  
    FROM sys.index_columns IC1     
    JOIN Sys.columns C      
       ON C.object_id = IC1.object_id      
       AND C.column_id = IC1.column_id      
       AND IC1.is_included_column = 1     
    WHERE IC1.object_id = IC2.object_id      
       AND IC1.index_id = IC2.index_id      
    GROUP BY  IC1.object_id,C.name,index_id     
       FOR XML PATH('')), 1, 2, '') IncludedColumns      
   FROM sys.index_columns IC2      
   --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables     
   GROUP BY  IC2.object_id ,IC2.index_id) tmp1     
   WHERE IncludedColumns IS NOT  NULL ) tmp2      
ON tmp2.object_id = I.object_id AND tmp2.index_id = I.index_id     
WHERE I.is_primary_key = 0 AND I.is_unique_constraint = 0   
--AND I.Object_id = object_id('Person.Address') --Comment for all tables   
--AND I.name = 'IX_Address_PostalCode' --comment for all indexes

根据您的需要调整查询:

  • sys.tables 到 sys.views
  • 删除 select 中的默认值
  • 删除/添加一些where条件

1
投票
DECLARE @T_IndexInfo TABLE
    (
      IndID NVARCHAR(128),
      ObjectID NVARCHAR(128),
      ColID NVARCHAR(128),
      IndexName NVARCHAR(128),
      TableName NVARCHAR(128),
      ColumnName NVARCHAR(128),
      KeyNo NVARCHAR(128),
      ColType NVARCHAR(128)
    )

INSERT  INTO @T_IndexInfo
        SELECT  I.IndID,
                SO.ID AS 'ObjectID',
                SK.ColID,
                I.Name AS 'IndexName',
                SO.Name AS 'TableName',
                SC.Name AS 'ColumnName',
                Sk.KeyNo,
                CASE WHEN Sk.KeyNo = 0 THEN 'Include'
                     ELSE 'Normal'
                END AS 'ColType'
        FROM    sys.sysindexes I
                INNER JOIN sys.sysobjects SO ON SO.ID = I.ID
                                                AND SO.xtype = 'U'
                INNER JOIN sys.sysindexkeys SK ON SK.IndID = I.IndID
                                                  AND SO.ID = SK.ID
                INNER JOIN sys.syscolumns SC ON SC.ID = SO.ID
                                                AND SC.ColID = SK.ColID
        WHERE   I.IndID > 0
                AND I.IndID < 255
                AND ( I.Status & 64 ) = 0
--                AND ( I.status & 2048 ) <> 2048   /******** comment this if PK's also need to be recreated *****/
        ORDER BY SO.Name,
                I.Name

DECLARE @T_Final TABLE
    (
      TableName NVARCHAR(128),
      IndexName NVARCHAR(128),
      NormalColumns NVARCHAR(MAX),
      IncludedColumns NVARCHAR(MAX)
    )

INSERT  INTO @T_Final
        SELECT DISTINCT
                TableName,
                IndexName,
                STUFF(( SELECT  ',[' + ColumnName + ']'
                        FROM    @T_IndexInfo
                        WHERE   IndID = I.IndID
                                AND ObjectID = I.ObjectID
                                AND ColType = 'Normal'
                        ORDER BY KeyNo
                      FOR
                        XML PATH('')
                      ), 1, 1, '') AS 'NormalColumns',
                STUFF(( SELECT  ',[' + ColumnName + ']'
                        FROM    @T_IndexInfo
                        WHERE   IndID = I.IndID
                                AND ObjectID = I.ObjectID
                                AND ColType = 'Include'
                      FOR
                        XML PATH('')
                      ), 1, 1, '') AS 'IncludedColumns'
        FROM    @T_IndexInfo I;

WITH indexCTE AS
    (   
    SELECT Table_Name, Column_Name --, Collation_Name 
    FROM information_schema.columns 
    WHERE Collation_Name IS NOT NULL AND Collation_Name = 'Modern_Spanish_CI_AS'
    ), 
    indexCTE2 AS
    (
    SELECT i.Name [Index Name], OBJECT_NAME(i.object_ID) [Table Name], c.Name [Column Name]
    FROM sys.indexes i 
    INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id
    INNER JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.OBJECT_ID
    WHERE EXISTS (SELECT 1 FROM indexCTE t1 WHERE t1.Table_Name = OBJECT_NAME(i.object_ID) AND t1.Column_Name = c.Name)
    )   

SELECT IndexName, TableName, NormalColumns, IncludedColumns
INTO #temp1
FROM @T_Final z INNER JOIN indexCTE2 x ON z.IndexName = x.[Index Name]

-- To generate CREATE INDEX SCRIPT
SELECT  'CREATE INDEX [' + IndexName + '] ON [' + TableName + '].('
        + NormalColumns + ')' + CASE WHEN IncludedColumns IS NULL THEN ''
                                     ELSE ' INCLUDE (' + IncludedColumns + ')'
                                END AS 'CreateScript'
FROM    #temp1

-- To generate DROP INDEX SCRIPT
SELECT  'DROP INDEX [' + TableName + '].[' + IndexName + ']' AS 'DropScript'
FROM    #temp1

删除表#temp1


0
投票

这有点偏离主题,但我想我还是会建议这个:

如果您不想继续在 sql server Management Studio 中执行脚本,您可以创建一个 runmyscripts.bat 文件,其中包含以下内容:

@echo off

echo Execute Scripts...

sqlcmd -i C:\Scripts\myscript1.sql
sqlcmd -i C:\Scripts\myscript2.sql

echo Scripts Complete.
echo Press any button to exit.
pause
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.