Есть ли способ предотвратить тупик при сохранении тех же запросов?
График взаимоблокировки показывает, что этот конкретный тупик был взаимоблокировкой преобразования, связанной с поиском по закладке (в данном случае поиск RID):
Как отмечается в вопросе, общий риск взаимоблокировки возникает из-за того, что запросы могут получить несовместимые блокировки для одних и тех же ресурсов в разных порядках. SELECT
Запрос необходимо получить доступ к индексу перед таблицей в связи с RID поиска, в то время как UPDATE
модифицирует запрос таблицы, а затем индекс.
Устранение тупика требует удаления одного из компонентов тупика. Ниже приведены основные параметры:
- Избегайте поиска RID, создав покрытие некластеризованного индекса. Это, вероятно, не практично в вашем случае, потому что
SELECT
запрос возвращает 26 столбцов.
- Избегайте поиска RID, создав кластерный индекс. Это может включать создание кластеризованного индекса для столбца
Proposal
. Это стоит рассмотреть, хотя кажется, что этот столбец имеет тип uniqueidentifier
, который может или не может быть хорошим выбором для кластеризованного индекса, в зависимости от более широких проблем.
- Избегайте использования общих блокировок при чтении, включив параметры
READ_COMMITTED_SNAPSHOT
или SNAPSHOT
базы данных. Это потребует тщательного тестирования, особенно в отношении любых встроенных блокировок. Код запуска также потребует тестирования, чтобы убедиться, что логика работает правильно.
- Избегайте использования общих блокировок при чтении с использованием
READ UNCOMMITTED
уровня изоляции для SELECT
запроса. Все обычные предостережения применяются.
- Избегайте одновременного выполнения этих двух запросов с помощью эксклюзивной блокировки приложения (см. Sp_getapplock ).
- Используйте подсказки блокировки таблицы, чтобы избежать параллелизма. Это больше, чем вариант 5, поскольку он может повлиять на другие запросы, а не только на два, указанных в вопросе.
Можно ли как-нибудь сделать X-Lock для индекса в транзакции обновления перед обновлением, чтобы обеспечить доступ к таблице и индексу в одном и том же порядке
Вы можете попробовать это, обертывание обновления в явной транзакции и выполнении SELECT
с XLOCK
намеком на некластеризованном значении индекса перед обновлением. Это полагается на то, что вы точно знаете текущее значение в некластеризованном индексе, правильно понимаете план выполнения и правильно предугадываете все побочные эффекты этой дополнительной блокировки. Он также полагается на то, что блокирующий двигатель недостаточно умен, чтобы избежать блокировки, если он считается избыточным .
Короче говоря, пока это возможно в принципе, я не рекомендую этого делать. Слишком легко что-то упустить или перехитрить себя творческим путем. Если вы действительно должны избежать этих тупиков (а не просто обнаружить их и повторить попытку), я бы посоветовал вам взглянуть на более общие решения, перечисленные выше.