Якщо у вас звичайний SQL Server (НЕ Azure) то за замовчуванням у вас рівень ізоляцій READ COMMITTED. Як при цьому виконується ваш апдейт:
- Встановлюється IU - intent update lock на таблицю. Він означає що ваш процес зібрався знайти в цій таблиці рядки, які треба оновити.
- Починають перебиратися рядки в пошуку тих, які треба оновити. Перед тим, як перевірити, чи варто оновлювати рядок, на неї ставиться U lock.
- Як тільки перший рядок для поновлення знайдена - встановлюється IX lock на таблицю. Ваш процес реально зібрався оновлювати дані.
- На конкретну рядок встановлюється X lock.
- установка U і X локов триває для всіх рядків, що призводить до встановлення X-локов на кожну оновлену рядок.
Таким чином, від моменту коли знайдена хоча б один запис для поновлення і до завершення транзакції (до кінця апдейта) на всіх оновлюваних рядках висять X-локи.
Одночасно з цим виконується SELECT:
- На таблицю встановлюється IS lock - intent shared
- На все обрані рядки встановлюються S lock.
Проблема в тому, що по правіалам сумісності локов S lock не можна поставити на сходинку, на якій вже стоїть X lock. Власне, це і є суть рівня ізоляцій READ COMMITTED - X lock означає що дані змінені іншим процесом, але зміни ще не вкоммітани - і через це їх не можна прочитати.
Таким чином, якщо у вас багато оновлюваних даних (вся таблиця, без where) або процес пошуку оновлюваних даних займає багато часу (where є, але мимо індексу / статистики / складне - варто подивитися план!) - то на час поновлення все висить, гальмує і падає з таймаут.
Обійти цю прикру обмеження можна включенням snapshot isolation і заміною READ COMMITTED на READ_COMMITTED_SNAPSHOT.
У READ_COMMITTED_SNAPSHOT SELECT буде вибирати дані з своєї власної копії, і не буде ставити S locks на рядки. Cоответственно, що не буде натикатися при установці S locks на чужі X locks і не буде їх чекати.
На SQL Azure READ_COMMITTED_SNAPSHOT включений за замовчуванням, і його не можна вимкнути.