Подтвердить что ты не робот

TABLOCK vs TABLOCKX

какая разница между TABLOCK и TABLOCKX http://msdn.microsoft.com/en-us/library/ms187373.aspx утверждает, что TABLOCK является общей блокировкой, а TABLOCKX является эксклюзивным замком. Является первым, возможно, только сортировкой индекса? И какова концепция совместного использования замка?

4b9b3361

Ответ 1

Большая разница, TABLOCK будет пытаться захватить "общие" блокировки и TABLOCKX эксклюзивные блокировки.

Если вы находитесь в транзакции и вы захватываете эксклюзивную блокировку таблицы, EG:

SELECT 1 FROM TABLE WITH (TABLOCKX)

Никакие другие процессы не смогут захватить любые блокировки в таблице, то есть все запросы, пытающиеся поговорить с таблицей, будут заблокированы до момента совершения транзакции.

TABLOCK только захватывает общую блокировку, общие блокировки освобождаются после выполнения оператора, если ваша изоляция транзакции READ COMMITTED (по умолчанию). Если уровень изоляции выше, например: SERIALIZABLE, общие блокировки сохраняются до конца транзакции.


Общие блокировки, хм, общие. Значение 2 транзакции могут одновременно считывать данные из таблицы, если они оба удерживают блокировку S или IS в таблице (через TABLOCK). Однако, если transaction A содержит общую блокировку таблицы, transaction B не сможет захватить исключительную блокировку до тех пор, пока не будут освобождены все общие блокировки. Прочитайте, какие блокировки совместимы с в msdn.


Оба подсказки заставляют db обходить более гранулированные блокировки (например, блокировки на уровне строк или страниц). В принципе, более гранулированные замки позволяют вам лучше concurrency. Например, одна транзакция может обновлять строку 100 в вашей таблице и другую строку 1000, в то же время, из двух транзакций (она становится сложной с блокировками страниц, но позволяет пропустить это).

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

В общем случае вы не использовали бы TABLOCK или TABLOCKX, если бы не были абсолютно необходимы его для некоторого края.

Ответ 2

Довольно старая статья на mssqlcity пытается объяснить типы блокировок:

Общие блокировки используются для операций, которые не изменяют или не обновляют данные, такие как оператор SELECT.

Блокировки обновлений используются, когда SQL Server намеревается изменить страницу, а затем продвигает блокировку страницы обновления до эксклюзивной блокировки страницы до фактического внесения изменений.

Эксклюзивные блокировки используются для операций модификации данных, таких как UPDATE, INSERT или DELETE.

То, что он не обсуждает, это Intent (который в основном является модификатором для этих типов блокировок). Блокировка Intent (Shared/Exclusive) - это блокировки, удерживаемые на более высоком уровне, чем реальная блокировка. Так, например, если ваша транзакция имеет блокировку X в строке, она также будет иметь блокировку IX на уровне таблицы (что останавливает другие транзакции от попытки получить несовместимую блокировку на более высоком уровне в таблице (например, схему блокировка модификации), пока ваша транзакция не завершится или не вернется).


Концепция "совместного использования" блокировки довольно проста: несколько транзакций могут иметь общую блокировку для одного и того же ресурса, тогда как только одна транзакция может иметь исключительную блокировку, а исключающая блокировка исключает любую транзакцию от получения или хранения Общий замок.

Ответ 3

Это скорее пример, где TABLOCK не работает для меня, и TABLOCKX.

У меня есть 2 сеанса, которые используют уровень изоляции по умолчанию (READ COMMITTED):

Сессия 1 - это явная транзакция, которая копирует данные с связанного сервера в набор таблиц в базе данных и занимает несколько секунд для запуска. [Например, он удаляет вопросы] Сессия 2 представляет собой инструкцию insert, которая просто вставляет строки в таблицу, в которую сеанс 1 не вносит изменений. [Пример, он вставляет ответы].

(На практике существует несколько сеансов, вставляющих несколько записей в таблицу одновременно, в то время как сеанс 1 выполняет свою транзакцию).

Сессия 1 должна запросить вставку таблицы 2, потому что она не может удалять записи, зависящие от записей, добавленных сеансом 2. [Пример: удаление вопросов, на которые не было ответа].

Итак, пока выполняется сеанс 1, и сеанс 2 пытается вставить, сеанс 2 каждый раз проигрывает в тупике.

Итак, инструкция удаления в сеансе 1 может выглядеть примерно так: DELETE tblA FROM tblQ LEFT JOIN tblX on... LEFT JOIN tblA a ON tblQ.Qid = tblA.Qid ГДЕ... a.QId IS NULL и...

Тупик, похоже, вызван конфликтом между запросом tblA, в то время как Session 2, [3, 4, 5,..., n] попытаются вставить в tblA.

В моем случае я мог бы изменить уровень изоляции транзакции сеанса 1 на SERIALIZABLE. Когда я это сделал: Менеджер транзакций отключил поддержку удаленных/сетевых транзакций.

Итак, я мог бы следовать инструкциям в принятом ответе здесь, чтобы обойти это: Менеджер транзакций отключил поддержку удаленных/сетевых транзакций

Но a) Мне было неудобно менять уровень изоляции на SERIALIZABLE в первую очередь - предположительно это ухудшает производительность и может иметь другие последствия, которые я не рассматривал, б) не понимал, почему это внезапно вызвало транзакции, чтобы иметь проблемы с работой на связанных серверах, и c) не знаю, какие возможные отверстия я могу открыть, включив сетевой доступ.

Похоже, что существует только 6 запросов в очень большой транзакции, которые вызывают проблемы.

Итак, я читал о TABLOCK и TabLOCKX.

Я не был абсолютно ясен в отношении различий и не знал, будет ли работать. Но казалось, что так и будет. Сначала я попробовал TABLOCK, и это, похоже, не имело никакого значения. Конкурирующие сессии генерировали одинаковые взаимоблокировки. Затем я попробовал TABLOCKX и больше не блокировал.

Итак, в шести местах все, что мне нужно было сделать, это добавить WITH (TABLOCKX).

Итак, инструкция удаления в сеансе 1 может выглядеть примерно так: DELETE tblA FROM tblQ q LEFT JOIN tblX x on... LEFT JOIN tblA a WITH (TABLOCKX) ON tblQ.Qid = tblA.Qid ГДЕ... a.QId IS NULL и...