web-dev-qa-db-fra.com

Pourquoi la suppression de clés étrangères prend-elle du temps?

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.

13
carlo.borreo

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.

12
Mikael Eriksson

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.

5
SqlWorldWide