Русский
Открыть в Telegram

Ветка SQL-ловушка: этот UPDATE может незаметно испортить данные в продакшене

13 сообщений · –
D
SQL-ловушка: этот UPDATE может незаметно испортить данные в продакшене Код корректный, PostgreSQL не выдаст ошибку. Но результат не так очевиден. Есть таблица товаров: CREATE TABLE products ( id INT PRIMARY KEY, price INT ); INSERT INTO products VALUES (1, 100); Применяем скидки: WITH discounts(id, amount) AS ( VALUES (1, 10), (1, 20) ) UPDATE products p SET price = p.price - d.amount FROM discounts d WHERE p.id = d.id; SELECT price FROM products; Что вернёт последний SELECT? А) 90 Б) 80 В) 70 Г) 80 или 90, результат не гарантирован Один запрос, две скидки на один товар. Как PostgreSQL обработает такой UPDATE? Подвох связан с поведением UPDATE ... FROM, о котором легко забыть даже при работе с реальными базами.
❤4👍4
8 · 327 ·
  1. .
    Очевидно что Г
  2. .
    Тут не в слоне дело, а в целом логика работы команды update
  3. В
    Почему в discounts на поле id нет уникального ключа? Для уникальности скидки на один товар. Либо, если логика допускает несколько скидок товару, их нужно обрабатывать последовательно
  4. S
    WITH discounts(id, amount) AS ( VALUES (1, 10), (1, 20) ) , discount_amounts(id, amount) AS ( SELECT id, SUM(amount) AS amount FROM discounts GROUP BY id ) UPDATE products p SET price = p.price - d.amount FROM discount_amounts d WHERE p.id = d.id; SELECT price FROM products;
  5. S
    Тут напрашивается уточнение в коде
  6. S
    В СУБД PostgreSQL этот запрос вернет 90. Официальная документация PostgreSQL строго оговаривает это поведение: если строка таблицы соединяется более чем с одной строкой из источников в блоке FROM, то для обновления будет использована только одна из строк, а остальные будут проигнорированы. Какая именно строка выберется — недетерминировано (непредсказуемо), но на практике для конструкции VALUES (1, 10), (1, 20) движок берет первую запись. Поэтому Postgres выполнит операцию 100 - 10 = 90, а скидку 20 просто отбросит.
    1. .
      Нет, правильный ответ Г
  7. К
    Похоже на очередной накат на Postgres. Проблема в том, кто пытается выполнить такой UPDATE. Т.е решение задачи в принципе должно предусматривать дедубль. И по хорошему нужно использовать merge - там гораздо труднее поймать неочевидное поведение - именно так в продакшене серьезные дяди и тети поступают.
  8. V
    При использовании UPDATE ... FROM с несколькими совпадающими строками в FROM результат непредсказуем. PostgreSQL применит UPDATE для каждой совпадающей строки, но порядок не гарантирован. Это не ошибка, а особенность поведения. PostgreSQL не запрещает такие запросы, но предупреждает, что результат может быть непредсказуемым.
  9. Б
    2 дисконта на один товар - явно логическая ошибка. Надо сразу с нескольких сторон ограничивать такие сценарии.
    👍1

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Границы индекса · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем