Тупик, вызванный оператором SELECT JOIN с SQL Server

При выполнении оператора SELECT с JOIN двух таблиц SQL Server, кажется, заблокировать обе таблицы выписки по отдельности. Например, по запросу вроде this:

SELECT ...
FROM
    table1
    LEFT JOIN table2
        ON table1.id = table2.id
    WHERE ...

Я обнаружил, что порядок блокировок зависит от условия WHERE. В оптимизатор запросов пытается создать план выполнения, который читает ровно столько ряды по мере необходимости. Итак, если условие WHERE содержит столбец table1 он сначала получит строки результатов из таблицы 1, а затем получит соответствующие строки из таблицы 2. Если столбец из таблицы2, он сделает это иначе круглый. Более сложные условия или использование индексов могут повлиять на решение оптимизатора запросов тоже.

Когда данные, считанные оператором, должны быть обновлены позже в транзакции с операторами UPDATE не гарантируется, что порядок UPDATE операторы соответствуют порядку, который использовался для чтения данных из двух таблиц. Если другая транзакция пытается прочитать данные, пока транзакция обновляет таблицы это может вызвать взаимоблокировку, когда оператор SELECT выполняется в между операторами UPDATE, потому что ни один из SELECT не может заблокировать первая таблица и UPDATE не может заблокировать вторую таблицу. Для пример:

T1: SELECT ... FROM ... JOIN ...
T1: UPDATE table1 SET ... WHERE id = ?
T2: SELECT ... FROM ... JOIN ... (locks table2, then blocked by lock on table1)
T1: UPDATE table2 SET ... WHERE id = ?

Обе таблицы представляют иерархию типов и всегда загружаются вместе. Так что имеет смысл загружать объект, используя SELECT с JOIN. Загрузка обеих таблиц по отдельности не даст оптимизатору запросов шанс найти лучший план исполнения. Но поскольку операторы UPDATE могут обновлять только одну таблицу в раз это может вызвать взаимоблокировки, когда объект загружается, пока объект обновляется другой транзакцией. Обновления объектов часто вызывают ОБНОВЛЕНИЯ на обе таблицы, когда свойства объекта принадлежат разным типам иерархия типов обновлена.

Я попытался добавить подсказки блокировки к оператору SELECT, но это не помогло изменить проблему. Это просто вызывает тупик в операторах SELECT, когда оба оператора пытаются заблокировать таблицы, а один оператор SELECT получает блокировку в порядке, обратном другому утверждению. Может быть, удастся загружать данные для обновлений всегда одним и тем же оператором, заставляя блокировки быть в том же порядке. Это предотвратит тупик между двумя транзакциями, которые хотите обновить данные, но не помешает транзакции, которая только читает данные в тупик, который должен иметь разные условия WHERE.

Единственный обходной путь, так что пока кажется, что чтение может не получать блокировки вообще. В SQL Server 2005 это можно сделать с помощью SNAPSHOT ISOLATION. В единственный способ для SQL Server 2000 - использовать изоляцию READ UNCOMMITED уровень.

Я хотел бы знать, есть ли еще одна возможность предотвратить SQL Server из-за возникновения этих взаимоблокировок?

8
задан Reboot 22 September 2010 в 08:01
поделиться