2010-02-19 17 views
27

Załóżmy Mam SQL Server 2005 tabeli, Tablex, z 2 indeksów na nim:
Zmień klucz podstawowy z nieklastrowany do Klastra

PK_TableX = PRIMARY KEY nieklastrowany na FieldA
IX_TableX_FieldB = klastrowych na FieldB

Chcę, aby PK był KLASTRY, a drugi indeks nie był KORZYSTANY.

Muszę założyć, że baza danych będzie w użyciu w momencie, gdy próbuję zmienić indeksy - więc moim głównym problemem, którego chcę uniknąć, jest to, że w pewnym momencie procesu nie będzie istniało ograniczenie PK na stole. Chcę być chroniony przed ryzykiem włożenia duplikatów kluczy.

Oznacza to, że nie mogę po prostu upuścić klucza głównego i odtworzyć go.

Proces ten należy wykonać za pomocą skryptu SQL, a nie SSMS.

Mam podejście, które moim zdaniem zadziała (opiszę to jako potencjalną odpowiedź), ale chciałbym je otworzyć, na wypadek, gdyby czegoś mi brakowało lub jest inny/lepszy sposób. Plus, może okazać się użyteczne dla innych w przyszłości

+0

Dlaczego chcesz grupować na klucz podstawowy? Czy to GUID czy INT? Czy większość twoich zapytań obejmuje dopasowanie PK? – awright18

+0

@ awright18 - klaster PK daje lepszą wydajność, w rzeczywistości jest złożonym kluczem podstawowym na 2 polach int, które najczęściej pytano na – AdaTheDev

Odpowiedz

39

1) upuść istniejącego indeksu klastrowego pierwszy (IX_TableX_FieldB):

DROP INDEX TableX.IX_TableX_FieldB 

2) Utwórz (tymczasowe) UNIQUE na unikalnych pól odwołuje się podstawowym kluczem

ALTER TABLE TableX 
    ADD CONSTRAINT UQ_TableX UNIQUE(FieldA) 

3) upuść klucz podstawowy

ALTER TABLE TableX 
    DROP CONSTRAINT PK_TableX 

4) Odtworzenie klucz podstawowy jako CLUSTERED

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

5) Rzuć tymczasowy UNIQUE

ALTER TABLE TableX 
    DROP CONSTRAINT UQ_TableX 

6) Dodać IX_TableX_FieldB ponownie jako nieklastrowany

CREATE NONCLUSTERED INDEX IX_TableX_FieldB ON TableX(FieldB) 
+1

To podejście, z którym podążyłem w końcu, wydaje się być najlepszym sposobem. – AdaTheDev

+0

To działa. Dlaczego to jest, gdy próbuję to zrobić za pomocą interfejsu użytkownika, który nie powiedzie się w pierwszym kroku i ponownie dodaje indeks klastrowany? – MetalPhoenix

+0

Jeśli masz zależne klucze obce lub ograniczenia, skorzystaj z tego http://dba.stackexchange.com/questions/48634/unable-to-drop-non-pk-index-because-it-is-referenced-ina-a- ograniczenie obcego klucza – qub1n

9

wiem, że to jest stary, ale to wykreśla wszystkie spadki FK, spadek pk, odtwarzanie pk, odtwarzanie FK. Zamień MYTABLE na nazwę tabeli.

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' jest niepoprawny, sprawdza kolumnę tożsamości, a nie kolumnę klucza głównego.Będzie działać oczywiście, jeśli kolumna klucza głównego jest kolumną tożsamości. –

+0

Jeśli masz pewność, że istnieje tylko jedna kolumna klucza głównego, zmień wartość 'set @ PKColumnName' na wartość' SELECT @ PKcolumnName = column_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE OBJECTPROPERTY (OBJECT_ID (nazwa ograniczenia), 'IsPrimaryKey') = 1 AND nazwa_tabeli = @PKTableName ' –

+0

Należy również pamiętać, że FILLFACTOR = 80 dla indeksu PK często nie jest optymalny. Wszystko zależy oczywiście od stołu. W moim przypadku anulowałem FILLFACTOR, aby uzyskać wartość domyślną (100%). –

Powiązane problemy