Чому скидання сторонніх ключів займає багато часу?


13

Я створив сценарій, який по черзі видаляє всі зовнішні ключі з бази даних, саме так:

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

Що мене дивує, це те, що сценарій займає тривалий час: в середньому 20 секунд на кожен DROP FK. Тепер я розумію, що створення FK може бути великою справою, тому що сервер повинен перейти і перевірити, чи обмеження FK не порушено з самого початку, а відкине? Що робить сервер, коли скидає FKs, що займає так довго? Це і для моєї цікавості, і для того, щоб зрозуміти, чи є спосіб зробити все швидше. Можливість видалення FK (а не просто їх відключення) дозволила б мені бути набагато швидшим під час міграції, а отже, мінімізувати час простою.


1
Можливо, інший процес розміщує блоки загальної схеми у вашій базі даних, змушуючи процес FK Fad дочекатися завершення цих процесів? Спробуйте запустити FK FK "drop" та негайно перевірити sp_who2 на блокування.
Даніель Хатмахер

Я забув зазначити, що в цій базі даних немає інших процесів. Але є й на інших базах даних на тому ж сервері.
carlo.borreo

Відповіді:


12

Для скасування обмеження потрібен замок Sch-M (модифікація схеми), який блокує інших запитувати таблицю під час модифікації. Ви, ймовірно, чекаєте, щоб отримати цей замок, і вам доведеться чекати, поки всі поточні запити проти цієї таблиці будуть закінчені.
Запуск запущеного запиту має на столі замок Sch-S (стабільність схеми), і цей замок несумісний із замком Sch-M.

З режимів блокування, блокування схем

База даних Engine використовує блокування модифікації схеми (Sch-M) під час операції з визначенням даних таблиці (DDL) таблиці, наприклад додавання стовпця або випадання таблиці. Під час його утримання замок Sch-M запобігає одночасному доступу до столу. Це означає, що замок Sch-M блокує всі зовнішні операції, поки замок не буде звільнений.

Деякі операції з мовою обробки даних (DML), наприклад, усічення таблиць, використовують блокування Sch-M для запобігання доступу до постраждалих таблиць шляхом одночасних операцій.

База даних Engine використовує блокування стабільності схеми (Sch-S) під час компіляції та виконання запитів. Замки Sch-S не блокують жодних замків транзакцій, включаючи ексклюзивні (X) замки. Тому інші транзакції, в тому числі транзакції з X замками на столі, продовжують виконуватись під час збирання запиту. Однак одночасні операції DDL і одночасні операції DML, які набувають замки Sch-M, не можуть бути виконані на столі.


Іноді навіть виділення таблиці в SSMS створить Sch-Sблокування, і я підозрюю, що це першопричина проблем ОП.
Джон Ейсбренер

5

Я пройду вас за прикладом, щоб ви зрозуміли, чому це зайняло тривалий час. Створення порожньої бази даних для цього тесту.

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 може придбати необхідний замок.

Для вашого випадку вам потрібно переконатися, що жоден сеанс не підтримує сумісний замок, що запобігає обмеженню падіння для придбання необхідного блокування / блокування.


Ніхто інший не використовував базу даних, але з іншого боку, я не можу виключити, що у мене було відкрите вікно цієї бази даних. Я зроблю ще один експеримент.
carlo.borreo

1
Коли виписка заяви очікує завершення, запустіть цей запит з іншого вікна. Це дасть вам те, що ви чекаєте. Отримайте запит звідси . У ньому більше деталей, ніж те, що я наводив у своєму прикладі.
SqlWorldWide
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.