Надеюсь, что кто-то с более глубокими знаниями в области postgres / database может поделиться некоторой информацией.
Справочная информация:
У меня есть база данных postgres v11, работающая с некоторыми данными. Теперь есть около 200 тыс. Операций, которые я хочу выполнить как отдельную транзакцию (все они должны быть успешными или не вносить изменений). Транзакции включают в себя комбинацию операторов INSERT и UPDATE, которые также включают в себя некоторые триггеры в базе данных.
Если я выполняю запрос в транзакции, то это занимает около 70 минут
BEGIN;
// statement
// statement
// statement
// ...
COMMIT;
Если я удалите окружающий блок транзакции и просто выполните запросы, тогда это займет 7 минут.
// statement
// statement
// statement
// ...
Теперь я подозреваю, что разница в производительности связана с хранением некоторых временных таблиц транзакций, которые сталкиваются с размером буфера, или проблемами индексации, что приводит к замедление, но так как у меня нет глубокого понимания внутренних органов Postgres, я фактически не знаю. Я попытался изменить различные настройки WAL, но без существенной разницы.
Итак, у меня есть 2 вопроса:
- Почему транзакция намного медленнее?
- Как можно ли выполнить пакет операций с возможностью отката без ущерба для производительности до этой степени?
РЕДАКТИРОВАТЬ 1
Дополнительная информация о таблицах и запросах
Я постараюсь дать как можно больше информации, не раскрывая подробностей (что мне не разрешено).
Существует 5 основных таблиц, связанных с этой транзакцией - accounts
, currencies
, transactions
, transaction_logs
, balance
.
transactions
Таблица имеет 3 внешних ключа - от 2 до accounts
и от 1 до currencies
.
* Таблица 1045 * имеет 2 внешних ключа - от 1 до accounts
и от 1 до currencies
.
transaction_logs
Таблица содержит 3 внешних ключа - от 1 до transactions
, от 1 до accounts
, 1 на currencies
.
Пакет транзакций начинается со вставки всех соответствующих счетов и валют. (около 10 000 учетных записей и 2 валют)
Далее это набор вставок и обновлений таблицы транзакций - вставки в группах по 300 строк в одной вставке, а обновления основаны на PK, поэтому только 1 грести за раз. Всего имеется около 140 тыс. Вставок и 60 тыс. Обновлений.
И вставки, и обновления в свою очередь выполняют триггеры, которые обновляют таблицу сальдо и вставляют 2 строки в таблицу транзакций.
Типичная вставка выглядит как
INSERT INTO transactions (from_account_id, to_account_id, currency_id, amount, metadata, status) VALUES (1, 1, 1, 10.00, '{"json":"blob"}', 'pending');
Типичное обновление выглядит как
UPDATE transactions SET status = 'finished' WHERE id = 1;
Среда программирования node.js
и драйвер pg
.
РЕДАКТИРОВАТЬ 2
Извиняюсь перед всеми за задержку с предоставлением дополнительной информации - я пытался создать закрытую тестовую среду, воспроизводящую ошибку. И при этом мне удалось приблизиться к сути проблемы. Сама структура кажется неактуальной. Замедление вызвано обновлением одной и той же строки снова и снова в рамках одной и той же транзакции.
Самым простым воспроизведением, которым я управлял, было создание таблицы с 2 полями, добавление нескольких строк, а затем многократно Обновление первого ряда. Без транзакции время работы остается относительно постоянным. Однако в рамках транзакции она начинает расти - около 100 тыс. Обновлений примерно в 3 раза выше, чем в начале. На моей машине общая разница во времени выполнения теста на 100 тыс. Обновлений была в 2,5 раза между транзакцией и версией без транзакции.
Если, однако, ваши данные более разнообразны - не обновление одной и той же строки, но разных строк, тогда проблема не происходит, и с хорошо распределенными данными транзакция на самом деле быстрее.
PS. Протестировал это также с v12 и работает примерно так же.
У кого-нибудь есть идеи, почему это происходит?
РЕДАКТИРОВАТЬ 3
Я создал хранилище для демонстрации этой проблемы https://github.com/DeadAlready/pg-test