Поделиться через


Укрупнение блокировки (компонент Database Engine)

Укрупнение блокировки — это процесс преобразования многих мелкогранулированных блокировок в меньшее число крупногранулированных блокировок, который снижает системные издержки, но повышает вероятность конфликта при одновременном доступе.

По мере того, как компонент SQL Server Database Engine получает низкоуровневые блокировки, он устанавливает блокировки намерений на объекты, содержащие объекты более низкого уровня.

  • При блокировке строк или диапазонов ключей индекса компонент Database Engine помещает блокировку намерений на страницы, содержащие эти строки или ключи.

  • При блокировании страниц компонент Database Engine помещает блокировку на объекты более высокого уровня, содержащие эти страницы. Кроме блокировки намерений объекта страничные блокировки создаются для следующих объектов.

    • Некластеризованные индексы конечного уровня

    • Страницы данных кластеризованных индексов

    • Страницы данных кучи

Компонент Database Engine может для одной и той же инструкции устанавливать блокировку как на строки, так и на страницы, чтобы свести к минимуму количество блокировок и исключить необходимость укрупнения этой блокировки. Например, компонент Database Engine может устанавливать блокировки страниц в некластеризованном индексе (если выбрано достаточное число последовательных ключей в узле индекса, чтобы удовлетворять условиям запроса) и блокировки строк в страницах данных.

Чтобы укрупнить блокировки, компонент Database Engine пытается изменить блокировку с намерением в таблице на соответствующую полную блокировку, например изменить блокировку с намерением монопольного доступа (IX) на монопольную (X) или блокировку с намерением совмещаемого доступа (IS) на совмещаемую (S). Если попытка укрупнения блокировки закончилась успешно, и получена полная блокировка таблицы, то освобождаются все блокировки кучи, сбалансированного дерева, страниц (PAGE), а также блокировки на уровне строк (RID), которые удерживались транзакцией на кучу или индекс. Если не удалось получить полную блокировку, в этот момент укрупнение блокировки не происходит и компонент Database Engine продолжит получать блокировки строк, ключей или страниц.

Компонент Database Engine не укрупняет блокировку строк или диапазона ключей до блокировки страниц, а повышает их прямо до блокировки таблиц. Точно так же блокировки страниц всегда укрупняются до блокировок таблиц. Вместо блокировки всей таблицы блокировка секционированных таблиц в SQL Server 2008 может быть укрупнена до уровня HoBT для связанной секции. Блокировка на уровне HoBT не обязательно блокирует выровненные идентификаторы HoBT этой секции.

ПримечаниеПримечание

Блокировки на уровне HoBT обычно повышают параллелизм, но создают потенциальный риск взаимоблокировки в том случае, когда транзакции блокируют различные секции и пытаются распространить монопольную блокировку на другие секции. В редких случаях гранулярность блокировки TABLE может оказаться более удачным решением.

Если попытка укрупнения блокировки заканчивается неудачей из-за конфликтующих блокировок, удерживаемых параллельными транзакциями, компонент Database Engine повторяет попытку для каждых дополнительных 1 250 блокировок, полученных транзакцией.

Каждое событие укрупнения происходит, прежде всего, на уровне одной инструкции компонента Transact-SQL. В начале события компонент Database Engine пытается укрупнить все блокировки, принадлежащие текущей транзакции, во всех таблицах, на которые ссылается активная инструкция, при условии, что она удовлетворяет требованиям порога повышения. Если событие укрупнения начинается до того, как инструкция получила доступ к таблице, попытки укрупнения блокировок для этой таблицы не предпринимаются. Если укрупнение блокировки прошло успешно, все блокировки, полученные транзакцией в предыдущей инструкции и все еще удерживаемые в момент начала события, повышаются, если на таблицу ссылается текущая транзакция и таблица включена в событие повышения.

Предположим, что сеанс выполняет следующие операции:

  • Начинает транзакцию.

  • Обновляет таблицу TableA. Этим формируются монопольные блокировки строк в таблице TableA, которые удерживаются до завершения транзакции.

  • Обновляет таблицу TableB. Этим формируются монопольные блокировки строк в таблице TableB, которые удерживаются до завершения транзакции.

  • Выполняет инструкцию SELECT, соединяющую таблицы TableA и TableC. План выполнения запроса предусматривает извлечение строк из таблицы TableA до извлечения строк из таблицы TableC.

  • Инструкция SELECT вызывает укрупнение блокировки при извлечении строк из таблицы TableA до того, как она получает доступ к таблице TableC.

Если укрупнение блокировки прошло успешно, укрупняются только блокировки, удерживаемые сеансом на таблицу TableA. Они включают как совмещаемые блокировки инструкции SELECT, так и монопольные блокировки предыдущей инструкции UPDATE. В то время как для определения необходимости укрупнения учитываются только блокировки, которые сеанс получил для инструкции SELECT в TableA, после успешного укрупнения блокировок все блокировки, удерживаемые сеансом в таблице TableA, укрупняются до монопольной блокировки таблицы, а все другие блокировки с более низкой гранулярностью, включая блокировки с намерением в TableA, освобождаются.

Попытки укрупнить блокировки в таблице TableB не предпринимаются, поскольку в инструкции SELECT не было активных ссылок на таблицу TableB. Точно так же не предпринимались попытки укрупнить блокировки в таблице TableC, потому что к моменту укрупнения к ней не был получен доступ.

Пороги укрупнения блокировок

Укрупнение блокировки включается в том случае, если не выключено для таблицы с помощью параметра ALTER TABLE SET LOCK_ESCALATION, и если выполняется одно из следующих условий.

  • Одна инструкция Transact-SQL получает более 5 000 блокировок в одной несекционированной таблице или индексе.

  • Одна инструкция Transact-SQL получает более 5 000 блокировок в одной секции секционированной таблицы, а параметр ALTER TABLE SET LOCK_ESCALATION установлен в значение AUTO.

  • Число блокировок в экземпляре компонента Database Engine превышает объем памяти или заданные пороговые значения.

Если блокировки не могут быть укрупнены из-за конфликтов блокировок, компонент Database Engine периодически инициирует укрупнение блокировки при получении каждых 1 250 новых блокировок.

Пороги укрупнения для инструкции Transact-SQL

Укрупнение блокировки инициируется в случаях, когда Transact-SQL получает по крайней мере 5 000 блокировок на одну ссылку таблицы или на одну ссылку индекса, или, если таблица секционирована, то на одну ссылку секции таблицы или на одну ссылку секции индекса. Например, укрупнение блокировки не происходит, если инструкция получает 3 000 в одном индексе и 3 000 в другом в одной и той же таблице. Аналогичным образом, укрупнение блокировки не происходит, если инструкция имеет самосоединение, а каждая ссылка на таблицу получает только 3 000 блокировок.

Укрупнение блокировок выполняется только для таблиц, доступ к которым был получен после запуска повышения. Предположим, что инструкция SELECT представляет собой соединение, получающее доступ к трем таблицам в следующей последовательности: TableA, TableB и TableC. Эта инструкция получает 3 000 блокировок строк в кластеризованном индексе таблицы TableA и по крайней мере 5 000 блокировок строк в кластеризованном индексе таблицы TableB, но еще не получила доступ к таблице TableC. Если компонент Database Engine обнаруживает, что инструкция получила, по крайней мере, 5 000 блокировок строк в таблице TableB, он пытается укрупнить все блокировки, удерживаемые текущей транзакцией в таблице TableB. Этот компонент также пытается укрупнить все блокировки, удерживаемые текущей транзакцией в таблице TableA, но, поскольку число блокировок в TableA меньше 5 000, попытка закончится неудачей. В таблице TableC такие попытки не предпринимаются, поскольку к ней не был получен доступ ко времени укрупнения блокировок.

Порог укрупнения для экземпляра компонента Database Engine

Каждый раз, когда количество блокировок превышает порог памяти для укрупнения блокировки, компонент Database Engine инициирует укрупнение блокировки. Порог памяти зависит от параметра конфигурации locks:

  • Если параметр locks имеет значение по умолчанию 0, порог укрупнения блокировок достигается, если память, используемая объектами блокировки, составляет 24 % от памяти компонента Database Engine, исключая память AWE. Для представления блокировки используется структура данных размером примерно 100 байт. Пороговое значение изменяется динамически, поскольку компонент Database Engine в процессе работы выделяет и освобождает память, пытаясь адаптироваться к изменяющейся нагрузке.

  • Если параметр locks имеет значение, отличное от 0, порог укрупнения блокировок составляет 40 процентов (или меньше, если памяти мало) от значения параметра locks.

Компонент Database Engine может выбирать для укрупнения любую активную инструкцию из сеанса, и для 1 250 новых блокировок он выбирает инструкции для повышения, если используемая блокировками память в экземпляре превышает порог повышения.

Укрупнение блокировок смешанного типа

Если происходит укрупнение блокировки, блокировка, выбранная для кучи или индекса, является достаточно сильной, чтобы удовлетворять требованиям самой ограничительной блокировки низкого уровня.

Предположим, что сеанс

  • Начинает транзакцию.

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

  • Выполняет инструкцию SELECT, которая ссылается на ту же таблицу.

Инструкция UPDATE получает следующие блокировки.

  • Монопольные (X) блокировки на обновляемые строки данных.

  • Блокировки с намерением монопольного доступа (IX) на страницы кластеризованного индекса, содержащего эти строки.

  • Блокировку IX на кластеризованный индекс и еще одну на таблицу.

Инструкция SELECT получает следующие блокировки.

  • Совмещаемые (S) блокировки на все считываемые строки данных, если они уже не защищены X-блокировкой инструкции UPDATE.

  • Блокировки с намерением совмещаемого доступа на все страницы кластеризованного индекса, содержащего эти строки, если эти страницы уже не защищены IX-блокировкой.

  • Не получает блокировки на кластеризованный индекс или таблицу, поскольку они уже защищены IX-блокировками.

Если инструкция SELECT получает достаточно блокировок для запуска укрупнения блокировок и оно проходит успешно, блокировка IX на таблицу преобразуется X-блокировку, а все блокировки строк, страниц и индексов освобождаются. Монопольными блокировками на таблицу защищаются все операции обновления и считывания.

Сокращение блокирования и укрупнения

В большинстве случаев компонент Database Engine обеспечивает оптимальную производительность при настройках по умолчанию для блокирования и укрупнения блокировок. Если экземпляру компонента Database Engine требуется большое количество блокировок и происходит частое их укрупнение, объем блокирования следует сократить следующим образом.

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

    • Уровень изоляции READ COMMITTED, если параметр базы данных READ_COMMITTED_SNAPSHOT включен (ON).

    • Уровень изоляции SNAPSHOT.

    • Уровень изоляции READ UNCOMMITTED. Это может использоваться только в системах с «грязным» чтением.

ПримечаниеПримечание

Изменение уровня изоляции затрагивает все таблицы экземпляра компонента Database Engine.

  • Используя табличные подсказки PAGLOCK или TABLOCK, чтобы компонент Database Engine использовал блокировку страниц, кучи или индекса вместо блокировки строк. Однако при этом увеличивается вероятность блокирования пользователями других пользователей, которые пытаются получить доступ к тем же данным. Следует использовать только в системах с небольшим количеством пользователей.

  • В секционированных таблицах параметр LOCK_ESCALATION инструкции ALTER TABLE позволяет произвести укрупнение до уровня HoBT (вместо уровня таблицы) или отключить укрупнение блокировок.

Можно также использовать флажки трассировки 1211 и 1224, чтобы отключить все или некоторые укрупнения блокировок. Дополнительные сведения см. в разделе Флаги трассировки (Transact-SQL). Отследить укрупнение блокировок можно с помощью события Приложение SQL Server Profiler Lock:Escalation. Дополнительные сведения см. в разделе Работа с приложением SQL Server Profiler.