繁体   English   中英

SQL Server 删除并重新创建表的索引

[英]SQL Server drop and recreate indexes of a table

我的 SQL Server 2008 出现问题。

我需要更改列类型,但索引阻止了更改。 但是由于数据库在多个客户端上,我不知道存在多少涉及该列的索引。

有没有办法以编程方式获取所有涉及该列的索引并删除它们,然后在alter table语句之后自动重新创建它们?

我听说禁用它们会因为类型的变化而弄乱表格。

我正在从 tinyint 更改为 smallint 类型。

禁用目标表上的所有索引

  ALTER INDEX Indexname ON Table DISABLE

然后改变列的数据类型

ALTER TABLE table
ALTER COLUMN columnname datatype

之后启用索引

ALTER INDEX Indexname ON Table REBUILD

也试试这个以了解表上带有列名的所有索引:

SELECT  OBJECT_SCHEMA_NAME(ind.object_id) AS SchemaName
      , OBJECT_NAME(ind.object_id) AS ObjectName
      , ind.name AS IndexName
      , ind.is_primary_key AS IsPrimaryKey
      , ind.is_unique AS IsUniqueIndex
      , col.name AS ColumnName
      , ic.is_included_column AS IsIncludedColumn
      , ic.key_ordinal AS ColumnOrder
FROM    sys.indexes ind
        INNER JOIN sys.index_columns ic
            ON ind.object_id = ic.object_id
               AND ind.index_id = ic.index_id
        INNER JOIN sys.columns col
            ON ic.object_id = col.object_id
               AND ic.column_id = col.column_id
        INNER JOIN sys.tables t
            ON ind.object_id = t.object_id
WHERE   t.is_ms_shipped = 0
ORDER BY OBJECT_SCHEMA_NAME(ind.object_id) --SchemaName
      , OBJECT_NAME(ind.object_id) --ObjectName
      , ind.is_primary_key DESC
      , ind.is_unique DESC
      , ind.name --IndexName
      , ic.key_ordinal

您可以使用以下脚本返回指定表/列的索引名称和类型。:

DECLARE @tableName SYSNAME
DECLARE @columnName SYSNAME

SET @tableName = 'Products'
SET @columnName = 'Name'

SELECT  IDX.name, IDX.type_desc, IndexedColumn
FROM    sys.tables TBL
INNER JOIN  sys.indexes IDX ON TBL.object_id = IDX.object_id
LEFT JOIN   sys.filegroups FG ON IDX.data_space_id = FG.data_space_id
CROSS APPLY
(   SELECT  COLS.Name
    FROM    sys.index_columns IXCL
    INNER JOIN  sys.columns COLS
                ON IXCL.object_id = COLS.object_id
                AND IXCL.column_id = COLS.column_id
    WHERE   IDX.object_id = IXCL.object_id
    AND     IDX.index_id = IXCL.index_id
    AND     COLS.name = @columnName
    AND     IDX.object_id = OBJECT_ID(@tableName)
) Indexed (IndexedColumn)
WHERE   TBL.object_id = OBJECT_ID(@tableName)

希望这有助于...

您可以使用内置工具来完成这项工作。 在 SQL Server Management Studio 中,单击“工具”,然后单击“选项”

展开“SQL Server 对象资源管理器”集并在其中单击“脚本”。

向下滚动到右侧的“表格和视图选项”。

找到名为“Script Indexes”的记录并将其设置为“True”,然后单击“确定”。

当您在对象资源管理器中右键单击您的表时,您可以选择“脚本为...”,选择这些选项中的任何一个现在都将编写索引以及表本身及其键的脚本。 复制所需的脚本,或者根据需要运行整个程序。

让我们假设基本情况(列不是任何约束的一部分,不是具有 XML 索引的 XML 列等),可以执行以下操作:

  • 使用select (...) from <sys.indexes + other sys schema views> FOR XML ...
  • 将每个 XML 作为表的扩展属性,例如使用前缀“IX_”(“IX_1”、“IX_2”等...)
  • 删除索引
  • 更改列
  • 收集具有前缀“IX_”的表的所有扩展属性
  • 根据其 XML 描述重新创建每个索引

下面是一些安全删除和重新创建索引的 SQL 示例:

IF(select object_id from sys.indexes  where [name] = 'IDX_RecordSubscription' and object_id = OBJECT_ID('[SystemSetup].[RecordSubscription]')) IS NOT NULL 
BEGIN 
    DROP INDEX [SystemSetup].[RecordSubscription].IDX_RecordSubscription 
 END

GO

CREATE  UNIQUE  INDEX
    IDX_RecordSubscription
ON
    [SystemSetup].[RecordSubscription]
    (
            Subscriber ASC,
    MenuItem ASC,
    RecordPrimaryKeyGuid ASC

    )
    WITH
    (
        PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = OFF
    ) ON [PRIMARY] 

GO

下面是一些 C# 代码,可以解决这个问题:

    protected override string GetCreateIndexScript(string uniquePart, string indexName, string fullTableName, string columnsPart)
    {
        return
            $"IF(select object_id from sys.indexes  where [name] = '{indexName}' and object_id = OBJECT_ID('{fullTableName}')) IS NOT NULL \r\n" +
            "BEGIN \r\n" +
            $"    DROP INDEX {fullTableName}.{indexName} \r\n " +
            "END\r\n\r\n" +
            "GO\r\n\r\n" +
            $"CREATE {uniquePart} INDEX\r\n" +
            $"\t{indexName}\r\n" +
            "ON\r\n" +
            $"\t{fullTableName}\r\n" +
            "\t(\r\n" +
            $"\t\t{columnsPart}\r\n" +
            "\t)\r\n" +
            "\tWITH\r\n" +
            "\t(\r\n" +
            "\t\tPAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = OFF\r\n" +
            "\t) ON [PRIMARY] ";
    }

这是一些 C#(可以转换为 SQL)来获取索引模式:

            const string selectStatement = "select " +
                                           "    SCHEMAs.name + '.' + tabs.name as OBJECT_ID,  " +
                                           "    ind.name as INDEX_NAME,  " +
                                           "    indcol.index_id AS INDEX_ID,  " +
                                           "    indcol.key_ordinal AS COLUMN_ORDINAL,  " +
                                           "    col.name AS COLUMN_NAME,  " +
                                           "    ind.is_unique " +
                                           "from " +
                                           "    sys.indexes ind " +
                                           "inner join " +
                                           "    sys.index_columns indcol     " +
                                           "on " +
                                           "    ind.object_id = indcol.object_id and " +
                                           "    ind.index_id = indcol.index_id " +
                                           "inner join " +
                                           "    sys.columns col " +
                                           "on " +
                                           "    col.object_id = indcol.object_id and " +
                                           "    col.column_id = indcol.column_id " +
                                           "inner join " +
                                           "    sys.tables tabs " +
                                           "on  " +
                                           "    tabs.object_id = ind.object_id " +
                                           "inner join " +
                                           "   sys.schemas schemas " +
                                           "on " +
                                           "   tabs.schema_id = schemas.schema_id " +
                                           "where  " +
                                           "    ind.type =2 and" +
                                           "   tabs.name <> 'sysdiagrams' " +
                                           "order by " +
                                           "    tabs.object_id, " +
                                           "    indcol.index_id, " +
                                           "    indcol.key_ordinal ";

            return DatabaseAdapter.Fill(selectStatement, null, null, null);

因此,基本上,您在这里执行最后一段代码,遍历结果(索引和列)并为每个返回的索引调用 GetCreateIndexScript。 然后,您可以安全地执行为删除和重新创建索引而创建的每个语句。

这种相同的方法可以与 TSQL 或其他语言一起使用。

这是我想删除/创建/禁用/启用(重建)Microsoft SQL Server 索引的方法:

CREATE VIEW dbo.vw_INDEX_TEXT AS
  SELECT
    x.[owner_name],
    x.[table_name],
    x.[index_name],
    
    /*
    ** DROP index
    */
    drop_sql = 'DROP INDEX ' + x.[index_name] + ' ON ' + x.[owner_name] + '.' + x.[table_name] + ';',

    
    /*
    ** CREATE index
    */
    create_sql = 
     'CREATE NONCLUSTERED INDEX ' + x.[index_name] + '
        ON ' + x.[owner_name] + '.' + x.[table_name] + '(' + 
          -- the common-delimited field list. 
         substring(
                (SELECT
                  ',' + [field_name] 
                FROM
                  (
                  SELECT 
                    [owner_name] = SCHEMA_NAME(O.schema_id),
                    [table_name] = O.name,
                    [index_name] = I.name,
                    [field_name] = C.name,
                    O.type,
                    S.key_ordinal,
                    S.is_descending_key,
                    S.is_included_column 
                  FROM 
                    sys.all_objects O inner join sys.indexes I       ON (O.object_id = I.object_id )
                                      inner join sys.index_columns S ON (O.object_id = S.object_id and I.index_id=S.index_id)
                                      inner join sys.columns C       ON (O.object_id = C.object_id and S.column_id = C.column_id)
                  WHERE 
                    I.index_id > 0 
                    AND SCHEMA_NAME(O.schema_id) = x.[owner_name] -- N'dbo' 
                    AND I.name                   = x.[index_name] -- the index name N'IDX_myindex' 
                    AND O.name                   = x.[table_name] -- the base table name N'mytable' 
                    AND O.type                   <> 'IT' 
                    AND I.is_primary_key         = 0 -- we are not creating primary keys  
                    AND I.is_unique_constraint   = 0 -- we are not creating unique constraints
                    AND (INDEXPROPERTY(I.object_id,I.name,'IsStatistics') <> 1)
                    AND (INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics') <> 1) 
                    AND (INDEXPROPERTY(I.object_id,I.name,'IsHypothetical') <> 1) 
                  ) as f
                FOR XML PATH('') 
            ), 2, 8000) -- we trim the leading comma 
            -- end of field list
        + ') 
     WITH (
          PAD_INDEX = OFF
         );',
         
    /*
    ** DISABLE index
    */
    disable_sql = 'ALTER INDEX ' + x.[index_name] + ' ON ' + x.[owner_name] + '.' + x.[table_name] + ' DISABLE;',

    /*
    ** ENABLE (REBUILD) index
    */
    enable_sql = 'ALTER INDEX ' + x.[index_name] + ' ON ' + x.[owner_name] + '.' + x.[table_name] + ' REBUILD;'

         
  FROM
    (SELECT 
      [owner_name] = SCHEMA_NAME(O.schema_id),
      [table_name] = O.name,
      [index_name] = I.name
      -- other interesting, but not used fields that might be useful for other index types:
      -- O.type,I.index_id,I.is_unique,
      -- prop= INDEXPROPERTY(I.object_id,I.name,'IsClustered'),
      -- I.is_padded,
      -- I.fill_factor,
      -- I.ignore_dup_key,I.allow_row_locks,I.allow_page_locks,I.is_disabled,I.data_space_id 
    FROM 
      sys.all_objects O INNER JOIN sys.indexes I on O.object_id=I.object_id 
    WHERE 
      I.index_id>0 
      -- AND O.name = @target_table_name
      AND O.type <> 'IT' 
      AND INDEXPROPERTY(I.object_id,I.name,'IsStatistics')     <> 1 
      AND INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics') <> 1 
      AND INDEXPROPERTY(I.object_id,I.name,'IsHypothetical')   <> 1 
      AND I.is_primary_key = 0 
      AND I.is_unique_constraint = 0  
    ) as x

只重新创建了最基本的索引,但我留下了一些额外的字段,这些字段可用作根据需要创建更复杂索引的基础。

命令位于视图的每个字段中。 使用exec实际执行这样的操作(为@target_table_name输入您的表名):

  Declare @target_table_name as sysname = 'mytable';
  Declare @sql_cmd           as table(ID int identity, cmd varchar(max) );
  Declare @this_cmd          as varchar(max) = '';
  Declare @ct                as int = 0;
  
  -- populate a temp table to store the results
  INSERT INTO @sql_cmd(cmd)
    SELECT
      cmd = enable_sql
    FROM
      dbo.vw_INDEX_TEXT 
    WHERE 
      table_name = @target_table_name
 
  -- the ID column will help us step though the rows one at a time
  SELECT @ct = max(ID) FROM @sql_cmd

  -- loop over all rows in the table, finding each individual command
  While (@ct > 0) Begin
    SELECT
      @this_cmd = cmd
    FROM
      @sql_cmd
    WHERE
      id = @ct
      
    select @this_cmd

    -- un-comment this line to actually run the command:
    -- exec (@this_cmd)
    
    SET @ct = @ct - 1
  End
    

请注意,示例中禁用了exec

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM