Почему создание таблицы с ограничением внешнего ключа в одной транзакции блокирует доступ к ссылочной таблице в другой? - PullRequest
3 голосов
/ 08 октября 2009

В одной транзакции я создаю таблицу, которая ссылается на другую таблицу. Во второй транзакции я запускаю SELECT-запрос к указанной таблице, но он блокируется первой транзакцией. Почему это так?

Транзакция A:

BEGIN TRAN
CREATE TABLE Child (id int NOT NULL,
                    parentId int NOT NULL REFERENCES Parent (id));

Транзакция B:

BEGIN TRAN
SELECT * FROM Parent; -- This query is blocked

Ответы [ 2 ]

6 голосов
/ 08 октября 2009

Глядя на блокировки в мониторе активности, мы видим, что первый процесс (создание таблицы) удерживает блокировку Sch-M на каком-либо объекте (он сообщает нам только идентификатор объекта, если мы смотрели Я ожидаю, что это будет родительский стол). В то же время второй процесс (выполнение выбора из родительской таблицы) блокируется при попытке получить блокировку Sch-S для того же объекта.

Глядя на документацию MSDN , мы видим, что эти блокировки представляют собой модификацию схемы (Sch-M) и стабильность схемы (Sch-S) - блокировка стабильности схемы необходима для второго запроса, чтобы гарантировать, что схема объекта не изменяется во время выполнения запроса, и блокировка изменения схемы удерживается любым, кто вносит изменение в объект.

Почему замок Sch-M получен на родительской таблице?

Поскольку план выполнения любого, кто изменяет строки в родительской таблице, изменился (в частности, изменение идентификатора или удаление строк) - при удалении строк из этой таблицы SQL-серверу теперь необходимо убедиться, что в дочернем элементе не было записей таблица, у которой был тот же parentId, что и у удаляемого вами.

Несмотря на то, что план выполнения вашего оператора select не изменится, для сервера SQL не требуется гранулярность блокировки, чтобы различать запросы, которые он может выполнять безопасно, и запросы, которые он не может - после того, как все изменения схемы не изменились что происходит очень часто, и поэтому нет необходимости оптимизировать подобные вещи в такой степени.

1 голос
/ 08 октября 2009

Вы можете проверить это в студии управления:

1) откройте новое окно А, запустите:

CREATE TABLE Parent (id int NOT NULL primary key);

2) откройте еще одно новое окно B, запустите:

BEGIN TRAN
CREATE TABLE Child (id int NOT NULL,
                    parentId int NOT NULL REFERENCES Parent (id));

3) вернитесь к окну A, запустите:

select * from parent

он заблокирован, работает и работает ..

4) откройте новое окно C, запустите:

sp_lock

вы можете увидеть блокировку DDL и блокировки X и IX на таблице, которые выдаются при попытке создать FK

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...