Операторы SQL Server SELECT, вызывающие блокировку
Мы используем базу данных SQL Server 2005 (без контроля версий строк) с огромным оператором select, и мы видим, что он блокирует выполнение других операторов (рассматривается с использованием sp_who2
). Я не осознавал, что операторы SELECT могут вызвать блокировку - могу ли я что-нибудь сделать, чтобы смягчить это?
6 ответов
SELECT может блокировать обновления. Правильно спроектированная модель данных и запрос вызовут только минимальную блокировку и не будут проблемой. "Обычная" подсказка WITH NOLOCK - почти всегда неправильный ответ. Правильный ответ - настроить ваш запрос, чтобы он не сканировал огромные таблицы.
Если запрос неуправляем, то сначала следует рассмотреть уровень ИЗОЛЯЦИИ SNAPSHOT, во-вторых, рассмотреть возможность использования SNAPSHOTS БАЗЫ ДАННЫХ, а последним параметром должен быть DIRTY READS (и лучше изменить уровень изоляции, чем использовать подсказку NOLOCK). Обратите внимание, что грязные чтения, как ясно указывает название, будут возвращать противоречивые данные (например, ваш общий лист может быть несбалансированным).
Из документации:
Shared (S)
блокировки позволяют читать параллельные транзакции(SELECT)
ресурс под пессимистическим контролем параллелизма. Для получения дополнительной информации см.Types of Concurrency Control
, Никакие другие транзакции не могут изменить данные, покаshared (S)
существуют блокировки на ресурсе.Shared (S)
блокировки ресурса снимаются, как только операция чтения завершается, если только уровень изоляции транзакции не установлен на повторяемое чтение или выше, или не используется подсказка блокировки для сохраненияshared (S)
блокировки на время транзакции.
shared lock
совместим с другой общей блокировкой или блокировкой обновления, но не с исключительной блокировкой.
Это означает, что ваш SELECT
запросы будут блокироваться UPDATE
а также INSERT
запросы и наоборот.
SELECT
query будет помещать временную разделяемую блокировку, когда он читает блок значений из таблицы, и удаляет ее, когда завершит чтение.
Пока блокировка существует, вы не сможете ничего сделать с данными в заблокированной области.
Два SELECT
запросы никогда не будут блокировать друг друга (если они не SELECT FOR UPDATE
)
Вы можете включить SNAPSHOT
уровень изоляции в вашей базе данных и использовать его, но учтите, что это не помешает UPDATE
запросы от блокировки SELECT
запросы (что, кажется, ваш случай).
Это, однако, помешает SELECT
запросы от блокировки UPDATE
,
Также обратите внимание, что SQL Server
, В отличие от Oracle
, использует менеджер блокировок и сохраняет его в списке связанных в памяти.
Это означает, что при большой нагрузке сам факт размещения и снятия блокировки может быть медленным, поскольку сам связанный список должен быть заблокирован потоком транзакций.
Чтобы выполнить грязное чтение, вы можете:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
//Your code here
}
или же
SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."
помните, что вы должны писать WITH (NOLOCK) после каждой таблицы, которую вы хотите прочитать
Вы можете установить уровень транзакции для чтения Uncommitted
Ты можешь использовать WITH(READPAST)
настольная подсказка. Это отличается от WITH(NOLOCK)
, Он получит данные до начала транзакции и никого не заблокирует. Представьте, что вы запустили оператор до начала транзакции.
SELECT * FROM table1 WITH (READPAST)
Вы также можете получить тупики:
"взаимоблокировки с участием только одной таблицы" http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx
и или неверные результаты:
Msgstr "Выбор в разделе ЧИТАТЬ СООТВЕТСТВУЮЩИЙ и ПОВТОРЯЮЩИЙСЯ ЧТЕНИЕ может вернуть неверные результаты.