2010-02-19 35 views
27

Giả sử tôi có một SQL Server 2005 bảng, TableX, với 2 chỉ số trên đó:
Thay đổi một Primary Key từ nonclustered để Clustered

PK_TableX = PRIMARY KEY nonclustered trên FieldA
IX_TableX_FieldB = Clustered trên FieldB

Tôi muốn chuyển PK thành CLUSTERED và chỉ mục còn lại là KHÔNG BAO GIỜ.

Tôi phải giả định rằng cơ sở dữ liệu sẽ được sử dụng tại thời điểm tôi cố gắng thay đổi các chỉ mục vòng - vì vậy mối quan tâm chính của tôi mà tôi muốn tránh, là tại một số điểm trong quá trình hạn chế PK sẽ không tồn tại trên bàn. Tôi muốn được bảo vệ chống lại bất kỳ nguy cơ của các phím trùng lặp được chèn vào.

tức là tôi không thể chỉ thả khóa chính và tạo lại khóa đó.

Quá trình này cần được thực hiện thông qua tập lệnh SQL chứ không phải qua SSMS.

Tôi có một cách tiếp cận mà tôi nghĩ rằng sẽ làm việc (tôi sẽ đăng nó như là một câu trả lời tiềm năng), nhưng muốn mở nó trong trường hợp tôi đang thiếu một cái gì đó hoặc có một cách tốt hơn. Thêm vào đó, nó có thể hữu ích cho những người khác trong tương lai

+0

Tại sao bạn muốn nhóm trên khóa chính? Nó là một GUID hoặc INT? Phần lớn truy vấn của bạn có bao gồm PK không? – awright18

+0

@ awright18 - PK nhóm cho hiệu suất tốt hơn, nó thực sự là một khóa chính phức hợp trên 2 trường int thường được truy vấn trên – AdaTheDev

Trả lời

39

1) Thả chỉ số hiện tại nhóm đầu tiên (IX_TableX_FieldB):

DROP INDEX TableX.IX_TableX_FieldB 

2) Tạo (tạm thời) hạn chế UNIQUE trên các lĩnh vực độc đáo tham chiếu trong chính chủ chốt

ALTER TABLE TableX 
    ADD CONSTRAINT UQ_TableX UNIQUE(FieldA) 

3) Thả PRIMARY kEY

ALTER TABLE TableX 
    DROP CONSTRAINT PK_TableX 

4) Tạo lại PRIMARY KEY như Clustered

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

5) Thả chế UNIQUE tạm

ALTER TABLE TableX 
    DROP CONSTRAINT UQ_TableX 

6) Thêm IX_TableX_FieldB lại như nonclustered

CREATE NONCLUSTERED INDEX IX_TableX_FieldB ON TableX(FieldB) 
+1

Đây là cách tiếp cận mà tôi đã đi với cuối cùng, có vẻ như là cách tốt nhất. – AdaTheDev

+0

Tính năng này hoạt động. Tại sao khi tôi cố gắng làm điều này bằng cách sử dụng giao diện người dùng mà nó không thành công trong bước đầu tiên và thêm lại chỉ mục nhóm? – MetalPhoenix

+0

Nếu bạn có khóa hoặc ràng buộc phụ thuộc nước ngoài, hãy làm theo http://dba.stackexchange.com/questions/48634/unable-to-drop-non-pk-index-because-it-is-referenced-in-a- ngoại khóa-ràng buộc – qub1n

9

Tôi biết điều này là cũ nhưng điều này sẽ kịch bản ra tất cả các giọt FK, thả pk, pk tái tạo, FK tái tạo. Thay thế MYTABLE bằng tên bảng của bạn.

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 '[email protected]+' 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 '[email protected]+' DROP CONSTRAINT '+ @PKName 
    PRINT @sql 

END 
SET @sql = 'ALTER TABLE '[email protected] +' ADD CONSTRAINT '[email protected]+' PRIMARY KEY CLUSTERED ('[email protected]+' 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 '[email protected]+' WITH NOCHECK ADD CONSTRAINT '+ @FKName+' FOREIGN KEY(['[email protected]+']) 
     REFERENCES ['[email protected]+'] (['[email protected]+'])' 
     PRINT(@sql) 
     SET @sql = 'ALTER TABLE '[email protected]+' CHECK CONSTRAINT '[email protected] 
     PRINT(@sql) 

     FETCH NEXT FROM table_cur2 INTO @table,@FKColumnName,@FKName 

     END 
CLOSE table_cur2 
DEALLOCATE table_cur2 
DROP TABLE FKAgainstTableList 
+0

´set @ PKcolumnName´ không chính xác, nó sẽ kiểm tra cột nhận dạng chứ không phải cột khóa chính.Nó sẽ làm việc tất nhiên nếu cột khóa chính là cột nhận dạng. –

+0

Nếu bạn chắc chắn chỉ có một cột khóa chính, hãy thay đổi 'set @ PKColumnName' bằng' SELECT @ PKcolumnName = column_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE OBJECTPROPERTY (OBJECT_ID (constraint_name), 'IsPrimaryKey') = 1 AND table_name = @PKTableName ' –

+0

Cũng lưu ý rằng một FILLFACTOR = 80 cho chỉ số PK thường không tối ưu. Tất cả phụ thuộc vào bảng tất nhiên. Trong trường hợp của tôi, tôi đã yêu cầu FILLFACTOR có mặc định (100%). –

Các vấn đề liên quan