Вы когда-нибудь слышали о подсказке NOLOCK в SQL Server? Это тема, которая часто вызывает споры среди разработчиков и администраторов баз данных. Некоторые утверждают, что использование подсказки NOLOCK может улучшить производительность, в то время как другие утверждают, что она уменьшает блокировки и тупики, не приобретая никаких блокировок. В этой статье мы рассмотрим, что происходит, когда мы используем подсказку NOLOCK в запросах и проанализируем приобретаемые блокировки.
Давайте начнем с рассмотрения запроса без подсказки NOLOCK:
SELECT * FROM Sales.SalesOrderHeader a CROSS JOIN Sales.SalesOrderHeader b
Когда мы анализируем приобретаемые блокировки этим запросом, мы видим общую блокировку на уровне базы данных. Эта блокировка не связана с подсказкой NOLOCK и приобретается при открытии соединения с базой данных, чтобы гарантировать, что другие сеансы не удаляют базу данных во время ее использования.
Затем мы видим блокировку намерений на уровне таблицы. Блокировка намерений указывает, что SQL Server намеревается приобрести общую блокировку (S) или исключительную блокировку (X) на ресурсы ниже в иерархии. В данном случае блокировка намерений предотвращает другую транзакцию от приобретения исключительной блокировки (X) на таблицу, гарантируя, что таблица не будет изменена во время выполнения оператора SELECT.
Наконец, мы видим общую блокировку на уровне страницы. Эта блокировка гарантирует, что данные на странице не будут изменены во время их чтения.
Теперь давайте посмотрим, как работает подсказка NOLOCK в сочетании с оператором обновления:
BEGIN TRAN
UPDATE Sales.SalesOrderHeader SET status = 5 WHERE SalesOrderID = 43659
Если мы снова запустим оператор SELECT и скрипт анализа блокировок, мы увидим, что запрос на общую блокировку страницы находится в состоянии ожидания. Это происходит потому, что он конфликтует с блокировкой намерений, приобретаемой сеансом обновления на странице. Хотя это помогает SQL Server избежать грязного чтения, это также вызывает блокировку. В данном случае оператор SELECT блокируется оператором UPDATE.
Теперь давайте попробуем выполнить тот же оператор SELECT с подсказкой NOLOCK:
SELECT * FROM Sales.SalesOrderHeader a WITH (NOLOCK) CROSS JOIN Sales.SalesOrderHeader b WITH (NOLOCK)
В этом случае мы видим, что только на уровне таблицы приобретается общая блокировка схемы. Он не приобретает общую блокировку на странице, что приводит к грязному чтению. Общая блокировка схемы на уровне таблицы важна, чтобы гарантировать, что схема таблицы не изменится во время чтения данных.
Даже если мы запустим оператор SELECT после оператора UPDATE, он все равно будет выполняться без блокировки, потому что он не пытается приобрести общие блокировки на страницах. Однако это также означает, что он будет выполнять грязное чтение.
Уровень изоляции READ UNCOMMITTED работает аналогично подсказке NOLOCK. Вместо указания подсказки для каждой таблицы вы можете установить уровень изоляции на READ UNCOMMITTED.
Важно отметить, что хотя подсказка NOLOCK может незначительно улучшить производительность, приобретая меньше блокировок по сравнению с операторами без подсказки, она также выполняет грязное чтение и может привести к нежелательным результатам. Поэтому важно использовать подсказку NOLOCK с осторожностью.
Если вам понравилась эта статья, не забудьте поставить лайк на моей странице в Facebook по адресу http://www.facebook.com/practicalSqlDba и посетить мой веб-сайт по адресу www.PracticalSqlDba.com.