История вопроса:
Массовое обновление данных востребовано при переносах, миграциях, исправлениях бизнес-логики. Типичный пример: нужно сменить статус у десятков миллионов строк в рабочей таблице, не останавливая сервис, сохраняя доступность и производительность.
Проблема:
Обычный UPDATE без ограничения работает долго, может привести к эскалации блокировок, блокирует таблицу и приводит к коллективному откату при ошибке. Требуется подход, который минимизирует влияние на пользователей и обеспечивает транзакционность.
Решение:
Пример кода:
-- Пример батч-обновления по 10 000 строк WHILE 1 = 1 BEGIN UPDATE TOP (10000) mytable SET status = 'archived', updated = GETDATE() WHERE status = 'active'; IF @@ROWCOUNT = 0 BREAK; END
Ключевые особенности:
Можно ли сделать массовый UPDATE за одну транзакцию и не заблокировать таблицу?
Как правило, нет. Большая транзакция блокирует таблицу/страницы и увеличивает риск блокировок и тайм-аутов. Лучше работать батчами.
Влияет ли наличие индексов на скорость массового обновления?
Да. Любое обновление индексируемых полей требует перестройки индекса для каждой строки. Иногда целесообразно временно убрать индексы, но это требует глубокого анализа.
Все строки обновляются атомарно при батч-обновлениях?
Нет, атомарность гарантируется только в пределах одной батчи (лимита строк/транзакции). Если батч прервётся, часть строк будет обновлена, часть — нет. Для true-атомарности — только полный UPDATE в одной транзакции, что опасно на больших объёмах.
Технический инженер решил обновить 10 млн строк одним запросом в продуктивной БД: UPDATE mytable SET status = 'archived'. Сайт "замер", откат занял десятки минут, страдала производительность.
Плюсы:
Запрос разбит на батчи по 10 000 строк с короткими транзакциями, обновление происходит в рабочее время без простоя.
Плюсы: