次のように、一度に1つずつ、データベースからすべての外部キーを削除するスクリプトを作成しました。
ALTER TABLE MyTable1 DROP CONSTRAINT FK_MyTable1_col1
ALTER TABLE MyTable2 DROP CONSTRAINT FK_MyTable2_col1
ALTER TABLE MyTable2 DROP CONSTRAINT FK_MyTable2_col2
驚いたのは、スクリプトに時間がかかることです。つまり、DROP FKごとに平均20秒かかります。サーバーがFK制約が最初から侵害されていないことを確認する必要があるため、FKを作成することは大きな問題になる可能性があることを理解しています。非常に時間がかかるFKをドロップするとき、サーバーは何をしますか?これは私自身の好奇心と、物事を速くする方法があるかどうかを理解するためです。 FKを(無効にするだけでなく)削除できると、移行中の速度が大幅に向上し、ダウンタイムを最小限に抑えることができます。
制約を削除するには、Sch-M(スキーマ変更)ロックが必要です。このロックにより、変更中に他のユーザーがテーブルをクエリできなくなります。おそらくそのロックを取得するために待機しており、そのテーブルに対して現在実行中のすべてのクエリが完了するまで待機する必要があります。
実行中のクエリには、テーブルにSch-S(スキーマ安定性)ロックがあり、そのロックはSch-Mロックと互換性がありません。
データベースエンジンは、列の追加やテーブルの削除などのテーブルデータ定義言語(DDL)操作中にスキーマ変更(Sch-M)ロックを使用します。保持されている間、Sch-Mロックはテーブルへの同時アクセスを防ぎます。これは、ロックが解除されるまで、Sch-Mロックがすべての外部操作をブロックすることを意味します。
テーブルの切り捨てなどの一部のデータ操作言語(DML)操作では、Sch-Mロックを使用して、同時操作による影響を受けるテーブルへのアクセスを防止します。
データベースエンジンは、クエリのコンパイルおよび実行時にスキーマ安定性(Sch-S)ロックを使用します。 Sch-Sロックは、排他(X)ロックを含むトランザクションロックをブロックしません。したがって、テーブルがXロックされているトランザクションを含む他のトランザクションは、クエリのコンパイル中も引き続き実行されます。ただし、並行DDL操作、およびSch-Mロックを取得する並行DML操作は、テーブルで実行できません。
例を紹介して、長い時間がかかった理由を理解できるようにします。このテスト用に空のデータベースを作成します。
CREATE DATABASE [TestFK]
GO
2つのテーブルを作成します。
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
Personテーブルに外部キー制約を作成します。
USE [TestFK]
GO
ALTER TABLE dbo.Person ADD CONSTRAINT FK_Person_AddressID FOREIGN KEY (AddressID)
REFERENCES dbo.Address(AddressID)
GO
両方のテーブルにデータを挿入します。
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
新しいクエリウィンドウを開いてこれを実行します(クエリが完了したらウィンドウを閉じないでください)。
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
別のクエリウィンドウを開き、これを実行します。
USE [TestFK]
GO
ALTER TABLE dbo.person DROP CONSTRAINT FK_Person_AddressID
ドロップ制約が引き続き実行中(待機中)であることがわかり、クエリを実行して、実行時間が長くなっている理由と待機しているロックを確認します。
SELECT * FROM sys.dm_os_waiting_tasks
WHERE blocking_session_id IS NOT NULL;
挿入操作をコミットすると、dropステートメントが必要なロックを取得できるようになるため、ドロップ制約はすぐに完了します。
あなたのケースでは、ドロップ制約が必要なロックを取得するのを防ぐ互換ロックを保持しているセッションがないことを確認する必要があります。