代码之家  ›  专栏  ›  技术社区  ›  AdaTheDev

将主键从非聚集更改为聚集

  •  30
  • AdaTheDev  · 技术社区  · 14 年前

    假设我有一个SQL Server 2005表Tablex,上面有两个索引:

    pk_tablex=字段a上未聚集的主键
    ix_tablex_fieldb=聚集在fieldb上

    我想将pk切换为集群,将另一个索引切换为非集群。

    我必须假设在我尝试更改索引轮的时候数据库将被使用——所以我想避免的主要问题是,在这个过程中的某个时刻,pk约束在表上是不存在的。我希望受到保护,避免插入重复密钥的风险。

    也就是说,我不能只删除主键并重新创建它。

    这个过程需要通过一个SQL脚本完成,而不是通过SSMS。

    我有一个我认为可行的方法(我会把它作为一个潜在的答案贴出来),但我想打开它,以防我错过什么或者有其他更好的方法。另外,它可能在将来对其他人有用

    2 回复  |  直到 14 年前
        1
  •  43
  •   AdaTheDev    14 年前

    1)先删除现有聚集索引(ix_tablex_fieldb):

       DROP INDEX TableX.IX_TableX_FieldB
    

    2)在主键中引用的唯一字段上创建(临时)唯一约束

        ALTER TABLE TableX
        ADD CONSTRAINT UQ_TableX UNIQUE(FieldA)
    

    3)删除主键

        ALTER TABLE TableX
        DROP CONSTRAINT PK_TableX
    

    4)将主键重新创建为群集

       ALTER TABLE TableX
       ADD CONSTRAINT PK_TableX PRIMARY KEY CLUSTERED(FieldA)
    

    5)删除临时唯一约束

       ALTER TABLE TableX
       DROP CONSTRAINT UQ_TableX
    

    6)将ix_tablex_fieldb重新添加为非聚集

       CREATE NONCLUSTERED INDEX IX_TableX_FieldB ON TableX(FieldB)
    
        2
  •  10
  •   Jerloldrartolf    12 年前

    我知道这是旧的,但这将脚本出所有的fk删除,pk删除,pk重新创建,fk重新创建。 用您的表名替换MyTable。

       IF  EXISTS (SELECT * FROM sys.tables WHERE object_id = OBJECT_ID(N'[dbo].[FKAgainstTableList]'))
    BEGIN 
        DROP TABLE FKAgainstTableList
    END
    --CREATE TABLE FKAgainstTableList (ForeignKey VARCHAR(30),[Table] VARCHAR(30))
    DECLARE @PKTableName VARCHAR(100), 
            @PKName varchar(100),
            @FKName varchar(100),
            @sql varchar(max),
            @PKcolumnName varchar(30),
            @table VARCHAR(100),
            @FKColumnName VARCHAR(100), 
            @parentColumnNumber int
    SET @PKTableName = 'MYTABLE'
    set @PKName = (SELECT name FROM sys.indexes WHERE OBJECT_NAME(object_id) = @PKTableName AND is_primary_key = 1)
    set @PKcolumnName = (SELECT name FROM sys.columns WHERE OBJECT_NAME(object_id) = @PKTableName AND is_identity =1)
    PRINT @PKcolumnName
    
     SELECT  OBJECT_NAME(sys.foreign_key_columns.parent_object_id) [Table],sys.columns.name [FKColumnName],sys.foreign_keys.name [FKName] 
        INTO FKAgainstTableList
        FROM sys.foreign_keys INNER JOIN sys.foreign_key_columns 
        ON sys.foreign_keys.object_id = sys.foreign_key_columns.constraint_object_id
        INNER JOIN sys.columns ON sys.columns.object_id = sys.foreign_keys.parent_object_id AND sys.columns.column_id = sys.foreign_key_columns.parent_column_id
        WHERE OBJECT_NAME(sys.foreign_keys.referenced_object_id) = @PKTableName
    
    
    DECLARE table_cur1 CURSOR  FOR
        SELECT  * FROM FKAgainstTableList
    
        PRINT @sql
    
    -------------------------------Disable constraint on FK Tables
    OPEN table_cur1
    FETCH NEXT FROM table_cur1 INTO @table,@FKColumnName,@FKName
    WHILE   @@FETCH_STATUS = 0
        BEGIN
            SET @sql ='ALTER TABLE '+@table+' DROP CONSTRAINT '+ @FKName
            PRINT @sql
            FETCH NEXT FROM table_cur1 INTO @table,@FKColumnName,@FKName
        END
    CLOSE table_cur1
    DEALLOCATE table_cur1
    --------------------------------DROP AND recreate CLUSTERED pk
    IF  EXISTS (SELECT 1 FROM sys.indexes WHERE object_id = OBJECT_ID(@PKTableName) AND name = @PKName)
    BEGIN
        SET @sql = 'ALTER TABLE '+@PKTableName+' DROP CONSTRAINT '+ @PKName
        PRINT @sql
    
    END
    SET @sql = 'ALTER TABLE '+@PKTableName +' ADD  CONSTRAINT '+@PKName+' PRIMARY KEY CLUSTERED ('+@PKcolumnName+' ASC)
    WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 80) ON [PRIMARY]'
    PRINT(@sql)
    
    --------------------------------Enable FK constraints on FK tables.
    DECLARE table_cur2 CURSOR  FOR
        SELECT  * FROM FKAgainstTableList
    OPEN table_cur2
    FETCH NEXT FROM table_cur2 INTO @table,@FKColumnName,@FKName
    WHILE   @@FETCH_STATUS = 0
        BEGIN
            SET @sql = 'ALTER TABLE '+@table+' WITH NOCHECK ADD  CONSTRAINT  '+ @FKName+' FOREIGN KEY(['+@FKColumnName+'])
            REFERENCES ['+@PKTableName+'] (['+@PKcolumnName+'])'
            PRINT(@sql)
            SET @sql = 'ALTER TABLE '+@table+' CHECK CONSTRAINT  '+@FKName
            PRINT(@sql)
    
            FETCH NEXT FROM table_cur2 INTO @table,@FKColumnName,@FKName
    
             END
    CLOSE table_cur2
    DEALLOCATE table_cur2
    DROP TABLE FKAgainstTableList