将主键从Nonclustered更改为Clustered

Ada*_*Dev 31 sql sql-server indexing sql-server-2005

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

字段B上的
Field_TIX_TableX_FieldB = CLUSTERED上的PK_TableX = PRIMARY KEY NONCLUSTERED

我想将PK切换为CLUSTERED,将另一个索引切换为NONCLUSTERED.

我必须假设数据库将在我尝试更改索引时使用 - 因此我想要避免的主要问题是,在该过程中的某个时刻,PK约束将不存在于表中.我想要保护免受任何插入重复键的风险.

即我不能只删除主键并重新创建它.

此过程需要通过SQL脚本完成,而不是通过SSMS完成.

我有一种方法,我认为它会起作用(我会把它作为一个潜在的答案发布),但是如果我错过了某些东西或者有另一种/更好的方法,我想打开它.此外,它可能在将来对其他人有用

Ada*_*Dev 44

1)首先删除现有的聚簇索引(IX_TableX_FieldB):

   DROP INDEX TableX.IX_TableX_FieldB
Run Code Online (Sandbox Code Playgroud)

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

    ALTER TABLE TableX
    ADD CONSTRAINT UQ_TableX UNIQUE(FieldA)
Run Code Online (Sandbox Code Playgroud)

3)放下PRIMARY KEY

    ALTER TABLE TableX
    DROP CONSTRAINT PK_TableX
Run Code Online (Sandbox Code Playgroud)

4)重新创建PRIMARY KEY作为CLUSTERED

   ALTER TABLE TableX
   ADD CONSTRAINT PK_TableX PRIMARY KEY CLUSTERED(FieldA)
Run Code Online (Sandbox Code Playgroud)

5)删除临时UNIQUE约束

   ALTER TABLE TableX
   DROP CONSTRAINT UQ_TableX
Run Code Online (Sandbox Code Playgroud)

6)重新添加IX_TableX_FieldB作为NONCLUSTERED

   CREATE NONCLUSTERED INDEX IX_TableX_FieldB ON TableX(FieldB)
Run Code Online (Sandbox Code Playgroud)


小智 13

我知道这是旧的,但这将编写所有FK drop,pk drop,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
Run Code Online (Sandbox Code Playgroud)

  • 另请注意,PK 指数的 FILLFACTOR=80 通常不是最佳的。当然,这一切都取决于表。在我的情况下,我省略了 FILLFACTOR 以使用默认值 (100%)。 (2认同)