Beperkingen van externe sleutels uitschakelen:
DECLARE @sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' NOCHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql @sql;
Opnieuw inschakelen:
DECLARE @sql NVARCHAR(MAX) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql @sql;
U kunt echter niet afkappen de tabellen, moet u ze in de juiste volgorde verwijderen. Als u moet afkappen moet u de beperkingen volledig laten vallen en ze opnieuw maken. Dit is eenvoudig te doen als uw externe sleutelbeperkingen allemaal eenvoudige beperkingen met één kolom zijn, maar zeker complexer als er meerdere kolommen bij betrokken zijn.
Hier is iets dat je kunt proberen. Om dit een onderdeel van je SSIS-pakket te maken, heb je een plaats nodig om de FK-definities op te slaan terwijl het SSIS-pakket draait (je zult dit niet allemaal in één script kunnen doen). Maak dus in een hulpprogrammadatabase een tabel:
CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
Dan kunt u in uw database een opgeslagen procedure hebben die dit doet:
DELETE other_database.dbo.PostCommand;
DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' ADD CONSTRAINT ' + fk.name + ' FOREIGN KEY ('
+ STUFF((SELECT ',' + c.name
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '')
+ ') REFERENCES ' +
QUOTENAME(OBJECT_SCHEMA_NAME(fk.referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.referenced_object_id))
+ '(' +
STUFF((SELECT ',' + c.name
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '') + ');
' FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;
INSERT other_database.dbo.PostCommand(cmd) SELECT @sql;
IF @@ROWCOUNT = 1
BEGIN
SET @sql = N'';
SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' DROP CONSTRAINT ' + fk.name + ';
' FROM sys.foreign_keys AS fk;
EXEC sp_executesql @sql;
END
Wanneer uw SSIS-pakket nu klaar is, zou het een andere opgeslagen procedure moeten aanroepen, die het volgende doet:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
Als je dit allemaal doet om te kunnen kappen in plaats van verwijderen, raad ik aan om gewoon de hit te nemen en een verwijdering uit te voeren. Gebruik misschien een in bulk gelogd herstelmodel om de impact van het logboek te minimaliseren. Over het algemeen zie ik niet hoe deze oplossing zo veel sneller zal zijn dan alleen een verwijdering in de juiste volgorde.
In 2014 heb ik hier een uitgebreidere post over gepubliceerd:
- Alle beperkingen voor externe sleutels in SQL Server verwijderen en opnieuw maken