J'ai créé un script qui, une à la fois, supprime toutes les clés étrangères d'une base de données, comme ceci:
ALTER TABLE MyTable1 DROP CONSTRAINT FK_MyTable1_col1
ALTER TABLE MyTable2 DROP CONSTRAINT FK_MyTable2_col1
ALTER TABLE MyTable2 DROP CONSTRAINT FK_MyTable2_col2
Ce qui me surprend, c'est que le script prend beaucoup de temps: en moyenne, 20 secondes pour chaque DROP FK. Maintenant, je comprends que la création d'un FK peut être un gros problème, car le serveur doit aller vérifier que la contrainte FK n'est pas violée depuis le début, mais qu'elle tombe? Que fait un serveur lors de la suppression de FK qui prend si longtemps? C'est à la fois pour ma propre curiosité et pour comprendre s'il existe un moyen d'accélérer les choses. Pouvoir supprimer FK (et pas seulement les désactiver) me permettrait d'être beaucoup plus rapide lors d'une migration, et donc de minimiser les temps d'arrêt.
La suppression d'une contrainte nécessite un verrou Sch-M (modification de schéma) qui empêchera les autres d'interroger la table pendant la modification. Vous attendez probablement pour obtenir ce verrou et devez attendre que toutes les requêtes en cours d'exécution sur cette table soient terminées.
Une requête en cours d'exécution a un verrou Sch-S (stabilité du schéma) sur la table et ce verrou est incompatible avec un verrou Sch-M.
De modes de verrouillage, verrous de schéma
Le moteur de base de données utilise des verrous de modification de schéma (Sch-M) pendant une opération DDL (table data definition language), comme l'ajout d'une colonne ou la suppression d'une table. Pendant le temps qu'il est maintenu, le verrou Sch-M empêche l'accès simultané à la table. Cela signifie que le verrou Sch-M bloque toutes les opérations extérieures jusqu'à ce que le verrou soit libéré.
Certaines opérations du langage de manipulation de données (DML), telles que la troncature de table, utilisent des verrous Sch-M pour empêcher l'accès aux tables affectées par des opérations simultanées.
Le moteur de base de données utilise des verrous de stabilité de schéma (Sch-S) lors de la compilation et de l'exécution des requêtes. Les verrous Sch-S ne bloquent aucun verrou transactionnel, y compris les verrous exclusifs (X). Par conséquent, d'autres transactions, y compris celles avec des verrous X sur une table, continuent de s'exécuter pendant la compilation d'une requête. Toutefois, les opérations DDL simultanées et les opérations DML simultanées qui acquièrent des verrous Sch-M ne peuvent pas être effectuées sur la table.
Je vais vous guider à travers un exemple donc, vous pouvez voir pourquoi cela prenait beaucoup de temps. Création d'une base de données vide pour ce test.
CREATE DATABASE [TestFK]
GO
Création de 2 tables.
USE [TestFK]
GO
CREATE TABLE dbo.[Address] (
ADDRESSID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
Address1 VARCHAR(50),
City VARCHAR(50),
[State] VARCHAR(10),
Zip VARCHAR(10));
GO
CREATE TABLE dbo.Person (
PersonID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
LastName VARCHAR(50) NOT NULL,
FirstName VARCHAR(50),
AddressID INT);
GO
Création d'une contrainte de clé étrangère sur la table Personne.
USE [TestFK]
GO
ALTER TABLE dbo.Person ADD CONSTRAINT FK_Person_AddressID FOREIGN KEY (AddressID)
REFERENCES dbo.Address(AddressID)
GO
Insérez des données dans les deux tableaux.
USE [TestFK]
GO
INSERT dbo.Address (Address1,City,[State],Zip)
SELECT '123 Easy St','Austin','TX','78701'
UNION
SELECT '456 Lakeview','Sunrise Beach','TX','78643'
GO
INSERT dbo.Person (LastName,FirstName,AddressID)
SELECT 'Smith','John',1
UNION
SELECT 'Smith','Mary',1
UNION
SELECT 'Jones','Max',2
GO
Ouvrez une nouvelle fenêtre de requête et exécutez-la (ne fermez pas la fenêtre une fois la requête terminée).
USE [TestFK]
GO
BEGIN TRAN
INSERT dbo.Person (LastName,FirstName,AddressID)
SELECT 'Smith1','John1',1
UNION
SELECT 'Smith1','Mary1',1
UNION
SELECT 'Jones1','Max1',2
Ouvrez une autre fenêtre de requête et exécutez-la.
USE [TestFK]
GO
ALTER TABLE dbo.person DROP CONSTRAINT FK_Person_AddressID
Vous verrez que vous supprimez la contrainte continuera à fonctionner (en attente) et exécutez maintenant la requête pour voir pourquoi elle s'exécute plus longtemps et quels verrous elle attend.
SELECT * FROM sys.dm_os_waiting_tasks
WHERE blocking_session_id IS NOT NULL;
Une fois que vous avez validé votre opération d'insertion, la contrainte de suppression se termine immédiatement car l'instruction de suppression peut désormais acquérir le verrou requis.
Pour votre cas, vous devez vous assurer qu'aucune session ne détient un verrou compatible, ce qui empêchera la contrainte de chute d'acquérir le ou les verrous nécessaires.