【问题标题】:How can I drop all indexes in a SQL database with one command?如何使用一个命令删除 SQL 数据库中的所有索引?
【发布时间】:2023-03-17 15:30:01
【问题描述】:

那么,如何使用一个命令删除 SQL 数据库中的所有索引?我有这个命令可以让我获得所有 20 条左右的 drop 语句,但是如何从这个“结果集”运行所有这些 drop 语句?

select * from vw_drop_idnex;

另一个给我相同列表的变体是:

SELECT  'DROP INDEX ' + ix.Name + ' ON ' + OBJECT_NAME(ID)  AS QUERYLIST
FROM  sysindexes ix
WHERE   ix.Name IS NOT null and ix.Name like '%pre_%'

我尝试执行“exec(从 vw_drop_idnex 中选择 cmd)”,但没有成功。我正在寻找类似于 for 循环并逐个运行查询的东西。

-----------

在 Rob Farleys 的帮助下,剧本的最终草稿是:

declare @ltr nvarchar(1024);
SELECT @ltr = ( select 'alter table '+o.name+' drop constraint '+i.name+';'
  from sys.indexes i join sys.objects o on  i.object_id=o.object_id
  where o.type<>'S' and is_primary_key=1
  FOR xml path('') );
exec sp_executesql @ltr;

declare @qry nvarchar(1024);
select @qry = (select 'drop index '+o.name+'.'+i.name+';'
  from sys.indexes i join sys.objects o on  i.object_id=o.object_id
  where o.type<>'S' and is_primary_key<>1 and index_id>0
for xml path(''));
exec sp_executesql @qry

【问题讨论】:

  • 我认为您添加“AS QUERYLIST”很有趣,实际上您需要的答案不应该使用它 - 因为 FOR XML PATH('') 将更好地连接未命名列中的字符串(即,没有标签)。
  • 酷 - 你已经把它整理好了。我的资料基于您的 sysindexes 查询,因为大多数人没有您的“vw_drop_idnex”副本。

标签: sql sql-server tsql


【解决方案1】:

你很亲密。

declare @qry nvarchar(max);
select @qry = 
(SELECT  'DROP INDEX ' + quotename(ix.name) + ' ON ' + quotename(object_schema_name(object_id)) + '.' + quotename(OBJECT_NAME(object_id)) + '; '
FROM  sys.indexes ix
WHERE   ix.Name IS NOT null and ix.Name like '%prefix_%'
for xml path(''));
exec sp_executesql @qry

【讨论】:

  • 非常感谢!我知道那种方法,但我希望得到一些不需要声明变量的东西。不过我可以让它工作。
  • 另外值得一提的是......你应该考虑在你的名字周围使用 quotename 函数,以防他们有空格。
  • 它不太好用。我收到一条消息,上面写着:Msg 102, Level 15, State 1, Line 1 '
  • 在我看来,您仍然在尝试命名该列。确保您没有“AS QUERYLIST”或其中的任何内容。调试时,将“exec sp_executesql @qry”行替换为“select @qry”以查看您将要运行的内容。到时候应该会更明显。
  • 鉴于这是大约 3 年后,我使用它并通过更改选择喜欢阅读来修复它:SELECT 'DROP INDEX [' + ix.name + '] ON ' + OBJECT_NAME(ID) + '; ' - 我的索引包含 + 符号并需要实际的索引名称像[MY INDEX+]一样被分隔。其他符号和空格也需要相同(可能包括前面提到的&lt; 符号?)
【解决方案2】:

这对我有用 我们跳过 sys 索引和约束

declare @qry nvarchar(max);
select @qry = (

    select  'IF EXISTS(SELECT * FROM sys.indexes WHERE name='''+ i.name +''' AND object_id = OBJECT_ID(''['+s.name+'].['+o.name+']''))      drop index ['+i.name+'] ON ['+s.name+'].['+o.name+'];  '
    from sys.indexes i 
        inner join sys.objects o on  i.object_id=o.object_id
        inner join sys.schemas s on o.schema_id = s.schema_id
    where o.type<>'S' and is_primary_key<>1 and index_id>0
    and s.name!='sys' and s.name!='sys' and is_unique_constraint=0
for xml path(''));

exec sp_executesql @qry

【讨论】:

    【解决方案3】:

    发件人:Stephen Hill's Bloggie

    DECLARE @indexName VARCHAR(128)
    DECLARE @tableName VARCHAR(128)
    
    DECLARE [indexes] CURSOR FOR
    
            SELECT          [sysindexes].[name] AS [Index],
                            [sysobjects].[name] AS [Table]
    
            FROM            [sysindexes]
    
            INNER JOIN      [sysobjects]
            ON              [sysindexes].[id] = [sysobjects].[id]
    
            WHERE           [sysindexes].[name] IS NOT NULL 
            AND             [sysobjects].[type] = 'U'
            --AND               [sysindexes].[indid] > 1
    
    OPEN [indexes]
    
    FETCH NEXT FROM [indexes] INTO @indexName, @tableName
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
            --PRINT 'DROP INDEX [' + @indexName + '] ON [' + @tableName + ']'
            Exec ('DROP INDEX [' + @indexName + '] ON [' + @tableName + ']')
    
            FETCH NEXT FROM [indexes] INTO @indexName, @tableName
    END
    
    CLOSE           [indexes]
    DEALLOCATE      [indexes]
    
    GO
    

    【讨论】:

    • 太棒了!它甚至包括一个用于测试的注释掉的打印行:)
    • 如果表上有一个约束,这将失败,因为只能使用 DROP CONSTRAINT 而不是 DROP INDEX 删除这些约束
    【解决方案4】:

    没有一个答案很适合我的需要。

    我需要一个同时删除备份唯一或主要约束的索引(除非这些索引在备份外键时无法删除)

    DECLARE @SqlScript NVARCHAR(MAX);
    
    
    SELECT @SqlScript = 
    (
    SELECT 
    '
    BEGIN TRY
    '+ CASE WHEN 1 IN (i.is_primary_key, i.is_unique_constraint) THEN
     '
     ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(i.object_id)) + '.' + QUOTENAME(t.name)  + ' DROP CONSTRAINT ' + QUOTENAME(i.name) + ';'
    else
     '
     DROP INDEX ' + QUOTENAME(i.name)  + ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(i.object_id)) + '.' + QUOTENAME(t.name)
     END+'
    
    END TRY
    BEGIN CATCH
    RAISERROR(''Could not drop %s on table %s'', 0,1, ' + QUOTENAME(i.name, '''') + ', ' + QUOTENAME(t.name, '''') + ')
    END CATCH
    '
    FROM sys.indexes i
    JOIN sys.tables t ON i.object_id = t.object_id
    WHERE i.type_desc IN ('CLUSTERED', 'NONCLUSTERED' )
    ORDER BY t.object_id, i.index_id DESC
    FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)');
    
    --Return script that will be run 
    SELECT @SqlScript AS [processing-instruction(x)]
    FOR XML PATH('');
    
    EXEC (@SqlScript);
    

    【讨论】:

      【解决方案5】:

      我必须在自己的案例中对已接受的答案进行小幅改进,主要是考虑到架构:

      declare @qry nvarchar(4000);
      select @qry = (select 'drop index ['+s.name+'].['+o.name+'].['+i.name+'];'
        from sys.indexes i join sys.objects o on i.object_id=o.object_id join sys.schemas s on o.schema_id=s.schema_id
        where o.type<>'S' and is_primary_key<>1 and index_id>0 and s.name<>'sys'
      for xml path(''));
      exec sp_executesql @qry
      

      另外:在我的情况下,它无法一次性运行,因为脚本变得超过 4000 个字符。我能想到的唯一解决方法是在内部选择上放置“前 20 名”并多次执行。

      【讨论】:

      • 要绕过字符数限制,如果您使用的是 SQL 2005 或更高版本,请使用 nvarchar(max) 作为 @qry 的数据类型。
      • @EdHarper 我试过了,它告诉我类型可以用作变量。我在 2008R2 (Express) 上。
      • 使用 varchar 而不是 nvarchar,你会得到 8000 个字符而不是 4000 个
      【解决方案6】:

      如果数据库中的任何表上的索引已经为零,则 OP 作为其问题的一部分发布的“最终草案”会出错。我需要解决这个问题。

      此外,我希望对流程进行更多控制,而不是删除 所有 表上的所有索引,因此我编写了以下存储过程来一次处理一个表:

      CREATE PROCEDURE [dbo].[sp_DropAllIndexesOnTable]
      
      @TableName varchar(1000)
      
      AS
      BEGIN
      SET NOCOUNT ON;
      
         DECLARE @DropCommand1 nvarchar(4000)
         DECLARE @DropCommand2 nvarchar(4000)
      
      --Create Temp Table to hold the names and table names of all Clustered Indexes
          SELECT o.name AS TableName, i.name AS IndexName
            INTO #AllClustered
            FROM sys.indexes i 
      INNER JOIN sys.objects o ON i.object_id=o.object_id
           WHERE o.type <> 'S'
             AND is_primary_key = 1
      
      --Create Temp Table to hold the names and table names of all NonClustered Indexes
          SELECT o.name AS TableName, i.name AS IndexName
            INTO #AllNonClustered
            FROM sys.indexes i 
      INNER JOIN sys.objects o ON i.object_id=o.object_id
           WHERE o.type <> 'S'
             AND is_primary_key <> 1 
             AND index_id > 0
      
      --Create DROP CONSTRAINT command for the Primary Key Constraint if there is one
          SELECT @DropCommand1 = ( SELECT 'ALTER TABLE dbo.['+ TableName +'] DROP CONSTRAINT ['+ IndexName +'];'
                                     FROM #AllClustered
                                    WHERE TableName = @TableName
                                      FOR xml path('') ); 
      
      --Create DROP INDEX command for the indexes on the table if there are any 
          SELECT @DropCommand2 = ( SELECT 'DROP INDEX [' + IndexName + '] ON dbo.['+ TableName +'];'
                                     FROM #AllNonClustered
                                    WHERE TableName = @TableName
                                      FOR xml path('') );
      
              IF (@DropCommand1 IS NULL AND @DropCommand2 IS NULL) PRINT 'No action taken, zero indexes found on table ' + @TableName
              IF @DropCommand1 IS NOT NULL EXEC sp_executesql @DropCommand1
              IF @DropCommand2 IS NOT NULL EXEC sp_executesql @DropCommand2
      
      DROP TABLE IF EXISTS #AllClustered
      DROP TABLE IF EXISTS #AllNonClustered
      
      END
      GO
      

      我循环浏览我的数据库中的特定表,我想使用循环删除索引,然后通过使用表名调用此过程来删除索引,然后立即重新创建更好的索引。这样,一次只有一个表没有索引。

      我这样做的原因和我这样做的桌子数量会让你头晕目眩,但我绝对需要这样的 proc!

      【讨论】:

        【解决方案7】:
        SELECT  'DROP INDEX [' + IX.NAME + '] ON ' + OBJECT_NAME(IX.OBJECT_ID) + '; '
        FROM  SYS.INDEXES IX
          JOIN SYS.OBJECTS O ON  IX.OBJECT_ID = O.OBJECT_ID
          INNER JOIN SYS.SCHEMAS S ON O.SCHEMA_ID = S.SCHEMA_ID
        WHERE 
          IX.NAME IS NOT NULL 
          AND O.TYPE <> 'S' 
          AND IS_PRIMARY_KEY <> 1 
          AND INDEX_ID > 0
          AND S.NAME != 'SYS' AND S.NAME!= 'SYS' AND IS_UNIQUE_CONSTRAINT = 0
        

        根据需要修改条件

        如果你想删除 PK 约束,你会在尝试删除索引时收到此消息:

        索引上不允许使用显式 DROP INDEX...它正在用于 PRIMARY KEY 约束强制执行。

        那么,用这个……

        SELECT 'ALTER TABLE [' + O.NAME + '] DROP CONSTRAINT  ' + IX.NAME + '; '
        FROM  SYS.INDEXES IX
          JOIN SYS.OBJECTS O ON  IX.OBJECT_ID = O.OBJECT_ID
          INNER JOIN SYS.SCHEMAS S ON O.SCHEMA_ID = S.SCHEMA_ID
        WHERE 
          IX.NAME IS NOT NULL 
          AND O.TYPE <> 'S' 
          AND INDEX_ID > 0
          AND S.NAME != 'SYS' AND S.NAME!= 'SYS'
        

        【讨论】:

          猜你喜欢
          • 2014-08-06
          • 2022-09-28
          • 2015-02-20
          • 2015-10-31
          • 1970-01-01
          • 2012-04-28
          • 1970-01-01
          • 2013-11-29
          • 2011-06-04
          相关资源
          最近更新 更多