Изменение первичного ключа с некластеризованного на кластеризованное
Предположим, что у меня есть таблица SQL Server 2005 TableX с двумя индексами на ней:
PK_TableX = ПЕРВИЧНЫЙ КЛЮЧ, НЕПРИСОЕДИНЕННЫЙ на FieldA
IX_TableX_FieldB = CLUSTERED на FieldB
Я хочу переключить PK на CLUSTERED, а другой индекс будет НЕОБХОДИМЫМ.
Я должен предположить, что база данных будет использоваться в момент, когда я пытаюсь изменить индексы вокруг - поэтому моя главная проблема, которую я хочу избежать, заключается в том, что в какой-то момент процесса ограничение PK не будет существовать на стол. Я хочу быть защищенным от любого риска вставки повторяющихся ключей.
то есть. Я не могу просто удалить первичный ключ и воссоздать его.
Этот процесс необходимо выполнить с помощью SQL script, а не через SSMS.
У меня есть подход, который, как я думаю, будет работать (я опубликую его как потенциальный ответ), но хотел бы открыть его на случай, если я что-то упустил или есть другой/лучший способ. Кроме того, это может оказаться полезным для других в будущем
Ответы
Ответ 1
1) Сначала отбросьте существующий кластерный индекс (IX_TableX_FieldB):
DROP INDEX TableX.IX_TableX_FieldB
2) Создайте (временное) ограничение UNIQUE для уникальных полей, на которые ссылается первичный ключ
ALTER TABLE TableX
ADD CONSTRAINT UQ_TableX UNIQUE(FieldA)
3) Снимите ПЕРВИЧНЫЙ КЛЮЧ
ALTER TABLE TableX
DROP CONSTRAINT PK_TableX
4) Восстановите главный ключ как CLUSTERED
ALTER TABLE TableX
ADD CONSTRAINT PK_TableX PRIMARY KEY CLUSTERED(FieldA)
5) Снимите временное ограничение UNIQUE
ALTER TABLE TableX
DROP CONSTRAINT UQ_TableX
6) Добавьте IX_TableX_FieldB обратно как NONCLUSTERED
CREATE NONCLUSTERED INDEX IX_TableX_FieldB ON TableX(FieldB)
Ответ 2
Я знаю, что это старый, но это будет script из всех капель FK, pk drop, pk rereate, 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 '[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