Есть ли способ предотвратить тупик при сохранении тех же запросов?
График взаимоблокировки показывает, что этот конкретный тупик был взаимоблокировкой преобразования, связанной с поиском по закладке (в данном случае поиск RID):

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