Опасность подсказки With(NoLock) в моем случае опасна?

Я читал и использовал (nolock) подсказки много раз, но у меня есть вопрос для конкретного случая.

В моем случае у меня есть один набор кода, который ссылается и обновляет одну базу данных.
Этот код должен был работать в однопоточном режиме. Несколько месяцев назад они решили сделать его многопоточным без изменения кода. Они сделали так, чтобы каждый "процессор кода" управлял отдельной группой магазинов.

Например, процессор 1 заботится о магазинах с 1 по 20, процессор 2 заботится о магазинах с 21 по 40 и так далее.

Все выглядело хорошо, пока мы не зашли в тупик. Взаимные блокировки всегда на страницах... если бы блокировки были только в строках, мы бы никогда не получили взаимные блокировки, поскольку данные одного процессора никогда не конфликтуют с данными другого процессора. Основываясь на этой теории, я решил использовать подсказки With(Nolock) для каждого выбора, который не нужно блокировать (еще не был введен в prod)... который заставил мои тупики исчезнуть в моей лаборатории.

Все выглядело хорошо, пока мой коллега не подошел ко мне с ЭТОЙ статьей, которая напугала меня до дерьма... потом я прочитал ЭТО...

Есть ли опасность использовать подсказку With(Nolock) в моем случае... где данные никогда не конфликтуют между процессорами?

3 ответа

Решение

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

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

Уберите ваши подсказки nolock и поместите базу данных в уровень изоляции моментальных снимков.

READ_COMMITTED_SNAPSHOT опция базы данных включена

См. https://technet.microsoft.com/en-us/library/ms191242(v=sql.105).aspx для получения дополнительной информации. Тем не менее, имейте в виду, что ваш диск, на котором хранится ваша база данных tempDB, имеет более высокий уровень ввода-вывода в изоляции моментальных снимков.

Похоже, что ваш запрос выбора является причиной мертвых блокировок. Это то, что может происходить. Вы можете выбирать и обновлять записи позже. Таким образом, при обновлении записей более 5000 sql сервер использует эскалацию блокировки и блокирует всю таблицу вместо блокировки строк.

Если ваша процедура похожа на -

select .......
--some coding here----
update statement

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

Решение -

  1. Использовать подсказку UPDLOCK - это позволит использовать общие блокировки, но не обновлять блокировки. Преобразуйте оператор select в -> select * from mytable с помощью (UPDLOCK,ROWLOCK) подсказка RowLOCK сохранит блокировку на уровне строки, а не на уровне страницы или таблицы. Это уменьшит взаимоблокировку

  2. Использовать изоляцию снимка

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

Другие вопросы по тегам