SQL-ревью: сколько строк затронет этот UPDATE
В ревью PR с миграцией цен часто встречается запрос вида:
UPDATE products SET price = price * 1.1 WHERE category_id IN ( SELECT id FROM categories WHERE parent_id = 42 );
Вопрос на собеседовании звучит просто: сколько строк затронет этот UPDATE. Правильный ответ — «не знаю без EXPLAIN», и это не уклонение, а единственно честная позиция.
Подзапрос может вернуть ноль строк, если parent_id = 42 не существует — тогда IN () не затронет ничего. Может вернуть миллион категорий, если иерархия устроена не так, как думает автор миграции. На проде это означает: либо миграция ничего не сделала и никто не заметил, либо она перезаписала половину таблицы ценой долгой блокировки строк.
Вторая часть вопроса — что будет с конкурентными чтениями на время выполнения этого UPDATE. В PostgreSQL он берёт ROW EXCLUSIVE на каждую затронутую строку, и если их миллион — транзакция может идти минутами, удерживая блокировки.
На собеседовании часто просят переписать это в безопасную форму: сначала SELECT count(*) с тем же условием, чтобы оценить масштаб, потом батчами по id с LIMIT, а не одним огромным UPDATE. Ещё спрашивают про идемпотентность миграции — что будет, если она упадёт на середине и запустится повторно.
Миграция без оценки количества строк — это не быстрый UPDATE, а неизвестная по времени блокировка на проде.
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки