Warum dauert das Löschen von Fremdschlüsseln lange?

13

Ich habe ein Skript erstellt, das nacheinander alle Fremdschlüssel aus einer Datenbank löscht:

ALTER TABLE MyTable1 DROP CONSTRAINT FK_MyTable1_col1
ALTER TABLE MyTable2 DROP CONSTRAINT FK_MyTable2_col1
ALTER TABLE MyTable2 DROP CONSTRAINT FK_MyTable2_col2

Was mich überrascht, ist, dass das Skript viel Zeit in Anspruch nimmt: durchschnittlich 20 Sekunden pro DROP FK. Jetzt verstehe ich, dass das Erstellen eines FK eine große Sache sein kann, weil der Server überprüfen muss, ob die FK-Einschränkung nicht von Anfang an verletzt wird, sondern fallen lässt? Was macht ein Server, wenn er FKs löscht, die so lange dauern? Dies ist sowohl für meine eigene Neugierde als auch um zu verstehen, ob es einen Weg gibt, die Dinge schneller zu machen. In der Lage zu sein, FK zu entfernen (nicht nur zu deaktivieren), würde es mir ermöglichen, während einer Migration viel schneller zu sein und daher die Ausfallzeiten zu minimieren.

carlo.borreo
quelle
1
Vielleicht legt ein anderer Prozess gemeinsam genutzte Schemasperren in Ihrer Datenbank ab und zwingt den Drop-FK-Prozess, auf den Abschluss dieser Prozesse zu warten? Führen Sie den Drop-FK aus und überprüfen Sie dann sofort, ob sp_who2 blockiert ist.
Daniel Hutmacher
Ich habe vergessen zu erwähnen, dass in dieser Datenbank keine anderen Prozesse ausgeführt werden. Es gibt aber auch andere Datenbanken auf demselben Server.
carlo.borreo

Antworten:

12

Das Löschen einer Einschränkung erfordert eine Sch-M-Sperre (Schema Modification), die andere Benutzer daran hindert, die Tabelle während der Änderung abzufragen. Sie warten wahrscheinlich darauf, diese Sperre zu erhalten, und müssen warten, bis alle derzeit ausgeführten Abfragen für diese Tabelle abgeschlossen sind.
Eine ausgeführte Abfrage verfügt über eine Sch-S-Sperre (Schema Stability) für die Tabelle und diese Sperre ist mit einer Sch-M-Sperre nicht kompatibel.

Von Sperrmodi, Schemasperren

Das Datenbankmodul verwendet Sch-M-Sperren (Schema Modification) während einer DDL-Operation (Table Data Definition Language), z. B. beim Hinzufügen einer Spalte oder Löschen einer Tabelle. Während dieser Zeit verhindert die Sch-M-Sperre den gleichzeitigen Zugriff auf die Tabelle. Dies bedeutet, dass die Sch-M-Sperre alle externen Vorgänge blockiert, bis die Sperre aufgehoben wird.

Einige DML-Vorgänge (Data Manipulation Language), z. B. das Abschneiden von Tabellen, verwenden Sch-M-Sperren, um den Zugriff auf betroffene Tabellen durch gleichzeitige Vorgänge zu verhindern.

Das Datenbankmodul verwendet Sch-S-Sperren (Schemastabilitätssperren) beim Kompilieren und Ausführen von Abfragen. Sch-S-Sperren blockieren keine Transaktionssperren, einschließlich exklusiver (X) -Sperren. Daher werden andere Transaktionen, einschließlich Transaktionen mit X-Sperren für eine Tabelle, weiterhin ausgeführt, während eine Abfrage kompiliert wird. Gleichzeitige DDL-Operationen und gleichzeitige DML-Operationen, die Sch-M-Sperren erwerben, können jedoch nicht für die Tabelle ausgeführt werden.

Mikael Eriksson
quelle
Manchmal führt sogar das Hervorheben der Tabelle in SSMS zu einer Sch-SSperre, und ich vermute, dass dies die Hauptursache für die Probleme des OP ist.
John Eisbrener
5

Ich werde Sie durch ein Beispiel führen, damit Sie sehen können, warum es lange gedauert hat. Erstellen einer leeren Datenbank für diesen Test.

CREATE DATABASE [TestFK]
GO

2 Tabellen erstellen.

 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

Erstellen einer Fremdschlüsseleinschränkung für die Personentabelle.

 USE [TestFK]
 GO
ALTER TABLE dbo.Person ADD CONSTRAINT FK_Person_AddressID FOREIGN KEY (AddressID)
REFERENCES dbo.Address(AddressID)
GO

Fügen Sie einige Daten in beide Tabellen ein.

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

Öffnen Sie ein neues Abfragefenster und führen Sie dieses aus (schließen Sie das Fenster nicht, wenn die Abfrage abgeschlossen ist).

   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

Öffnen Sie ein anderes Abfragefenster und führen Sie dieses aus.

USE [TestFK]
GO
ALTER TABLE dbo.person DROP CONSTRAINT FK_Person_AddressID

Sie werden feststellen, dass die Drop-Einschränkung weiterhin ausgeführt wird (wartet), und führen Sie nun die Abfrage aus, um festzustellen, warum sie länger ausgeführt wird und auf welche Sperren sie wartet.

SELECT * FROM sys.dm_os_waiting_tasks 
WHERE blocking_session_id IS NOT NULL; 

Sobald Sie Ihre Einfügeoperation festgeschrieben haben, wird die Drop-Einschränkung sofort abgeschlossen, da die Drop-Anweisung jetzt die erforderliche Sperre erhalten kann.

In Ihrem Fall müssen Sie sicherstellen, dass keine Sitzung über eine kompatible Sperre verfügt, um zu verhindern, dass die Drop-Einschränkung die erforderlichen Sperren erhält.

SqlWorldWide
quelle
Niemand anderes benutzte die Datenbank, aber andererseits kann ich nicht ausschließen, dass ich ein offenes Fenster in dieser Datenbank hatte. Ich werde ein weiteres Experiment machen.
carlo.borreo
1
Wenn Ihre drop-Anweisung darauf wartet, beendet zu werden, führen Sie diese Abfrage in einem anderen Fenster aus. Das gibt dir, worauf du wartest. Holen Sie sich die Abfrage von hier . Es enthält mehr Details als ich in meinem Beispiel angegeben habe.
SqlWorldWide