Mengapa menjatuhkan kunci asing butuh waktu lama?

13

Saya telah membuat skrip yang, satu per satu, menghapus semua kunci asing dari database, seperti ini:

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

Yang mengejutkan saya adalah skripnya membutuhkan waktu lama: rata-rata, 20 detik untuk setiap DROP FK. Sekarang, saya mengerti bahwa membuat FK mungkin merupakan masalah besar, karena server harus pergi dan memeriksa bahwa batasan FK tidak dilanggar sejak awal, tetapi menurun? Apa yang dilakukan server ketika menjatuhkan FK yang membutuhkan waktu begitu lama? Ini baik untuk keingintahuan saya sendiri, dan untuk memahami jika ada cara untuk membuat segalanya lebih cepat. Mampu menghapus FK (tidak hanya menonaktifkannya) akan memungkinkan saya menjadi lebih cepat selama migrasi, dan karenanya meminimalkan waktu henti.

carlo.borreo
sumber
1
Mungkin proses lain menempatkan kunci skema bersama pada database Anda, memaksa proses drop FK menunggu proses-proses tersebut selesai? Coba jalankan drop FK dan kemudian segera periksa sp_who2 untuk memblokir.
Daniel Hutmacher
Saya lupa menyebutkan, tidak ada proses lain yang berjalan pada database ini. Tetapi ada pada database lain di server yang sama.
carlo.borreo

Jawaban:

12

Menjatuhkan kendala membutuhkan kunci Sch-M (Modifikasi Skema) yang akan memblokir orang lain untuk meminta tabel selama modifikasi. Anda mungkin menunggu untuk mendapatkan kunci itu dan harus menunggu sampai semua pertanyaan yang berjalan saat ini terhadap tabel itu selesai.
Kueri yang berjalan memiliki kunci Sch-S (Stabilitas Skema) di atas meja dan kunci itu tidak kompatibel dengan kunci Sch-M.

Dari Mode Kunci, Skema Kunci

Mesin Database menggunakan kunci skema modifikasi (Sch-M) selama operasi bahasa definisi data tabel (DDL), seperti menambahkan kolom atau menjatuhkan tabel. Selama dipegang, kunci Sch-M mencegah akses bersamaan ke meja. Ini berarti kunci Sch-M memblokir semua operasi di luar hingga kunci dilepaskan.

Beberapa operasi bahasa manipulasi data (DML), seperti pemotongan tabel, menggunakan kunci Sch-M untuk mencegah akses ke tabel yang terpengaruh oleh operasi bersamaan.

Mesin Database menggunakan kunci skema stabilitas (Sch-S) ketika mengkompilasi dan mengeksekusi query. Kunci Sch-S tidak memblokir kunci transaksional, termasuk kunci eksklusif (X). Oleh karena itu, transaksi lain, termasuk yang dengan kunci X di atas meja, terus berjalan saat kueri sedang dikompilasi. Namun, operasi DDL bersamaan, dan operasi DML bersamaan yang memperoleh kunci Sch-M, tidak dapat dilakukan di atas meja.

Mikael Eriksson
sumber
Kadang-kadang bahkan menyoroti tabel di SSMS akan membuat Sch-Skunci, dan saya curiga ini adalah penyebab utama masalah OP.
John Eisbrener
5

Saya akan memandu Anda melalui contoh, jadi, Anda dapat melihat mengapa itu membutuhkan waktu lama. Membuat database kosong untuk pengujian ini.

CREATE DATABASE [TestFK]
GO

Membuat 2 tabel.

 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

Membuat batasan Kunci Asing di tabel Orang.

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

Masukkan beberapa data ke dalam kedua tabel.

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

Buka jendela permintaan baru dan jalankan ini (jangan tutup jendela setelah permintaan selesai).

   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

Buka jendela permintaan lain dan jalankan ini.

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

Anda akan melihat Anda menjatuhkan batasan akan terus berjalan (menunggu) dan sekarang jalankan kueri untuk melihat mengapa itu berjalan lebih lama dan kunci apa yang ditunggu.

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

Setelah Anda melakukan operasi penyisipan Anda, batasan drop akan selesai segera karena sekarang pernyataan drop dapat memperoleh kunci yang diperlukan.

Untuk kasus Anda, Anda perlu memastikan tidak ada sesi memegang kunci yang kompatibel yang akan mencegah drop drop untuk mendapatkan kunci / kunci yang diperlukan.

SqlWorldWide
sumber
Tidak ada orang lain yang menggunakan database, tetapi di sisi lain, saya tidak dapat mengecualikan bahwa saya memiliki jendela terbuka pada database ini. Saya akan membuat percobaan lain.
carlo.borreo
1
Ketika pernyataan drop Anda menunggu untuk selesai jalankan query ini dari jendela lain. Itu akan memberi Anda apa yang Anda tunggu. Dapatkan kueri dari sini . Ini memiliki lebih banyak detail daripada apa yang saya berikan dalam contoh saya.
SqlWorldWide