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

时间:2013-07-05 12:17:47

标签: sql sql-server sql-server-2008 sql-server-2008-r2

我的SQL Server 2008中存在这种情况。

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

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

我听说禁用它们会使表格变得混乱,因为类型会发生变化。

我正在从tinyint变为smallint类型。

7 个答案:

答案 0 :(得分:5)

禁用目标表上的所有索引

  ALTER INDEX Indexname ON Table DISABLE

然后改变列的数据类型

ALTER TABLE table
ALTER COLUMN columnname datatype

之后启用索引

ALTER INDEX Indexname ON Table REBUILD

答案 1 :(得分:4)

还尝试通过列名来了解表中的所有索引:

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

答案 2 :(得分:2)

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

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)

希望这有助于......

答案 3 :(得分:2)

您可以使用内置工具完成此项工作。在SQL Server Management Studio中,单击"工具"那么"选项"

展开" SQL Server对象资源管理器"设置并在其中,单击" Scripting"。

向下滚动到"表和视图选项"在右边。

找到名为"脚本索引"的记录并将其设置为" True",然后单击“确定”。

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

答案 4 :(得分:0)

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

  • 使用select (...) from <sys.indexes + other sys schema views> FOR XML ...
  • 以XML格式生成索引描述
  • 将每个XML作为表的扩展属性,例如命名为 带有前缀'IX_'('IX_1','IX_2'等等......)
  • drop indices
  • alter column
  • 收集具有前缀“IX _”
  • 的表的所有扩展属性
  • 根据其XML描述重新创建每个索引

答案 5 :(得分:0)

以下是安全删除和重新创建索引的示例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或其他语言一起使用。

答案 6 :(得分:0)

这是我想删除/创建/禁用/启用(重建)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