На одном моем сервере разработки тестовая транзакция (серия обновлений и т. Д.) Выполняется примерно за 2 минуты. На рабочем сервере это около 25 минут.
Сервер читает файл и вставляет записи. Он начинается быстро, но затем идет все медленнее и медленнее по мере продвижения. Для каждой вставляемой записи имеется сводное обновление таблицы, и именно это обновление постепенно замедляется. Это агрегатное обновление запрашивает таблицу, в которую выполняется запись, со вставками.
Конфигурация отличается только в max_worker_processes (разработка 8, версия 16), shared_buffers (dev 128MB, prod 512MB), wal_buffers (Dev 4MB, prod 16MB).
Я попытался настроить несколько конфигов, а также выгрузил всю базу данных и заново сделал initdb на тот случай, если он не был обновлен (до 9.6) правильно. Ничего не сработало.
Я надеюсь, что кто-то, имеющий опыт в этом, может сказать мне, что искать.
Редактировать: После получения некоторых комментариев я смог выяснить, что происходит, и приступить к работе, но я думаю, что должен быть лучший путь. Во-первых, что происходит, это:
Сначала в таблице нет данных для соответствующего индекса, postgresql разрабатывает этот план. Обратите внимание, что в таблице есть данные, которые не имеют ничего общего с соответствующим индексом «businessIdentifier» или «номер транзакции».
Aggregate (cost=16.63..16.64 rows=1 width=4) (actual time=0.031..0.031 rows=1 loops=1)
-> Nested Loop (cost=0.57..16.63 rows=1 width=4) (actual time=0.028..0.028 rows=0 loops=1)
-> Index Scan using transactionlinedateindex on "transactionLine" ed (cost=0.29..8.31 rows=1 width=5) (actual time=0.028..0.028 rows=0 loops=1)
Index Cond: ((("businessIdentifier")::text = '36'::text) AND ("reconciliationNumber" = 4519))
-> Index Scan using transaction_pkey on transaction eh (cost=0.29..8.31 rows=1 width=9) (never executed)
Index Cond: ((("businessIdentifier")::text = '36'::text) AND (("transactionNumber")::text = (ed."transactionNumber")::text))
Filter: ("transactionStatus" = 'posted'::"transactionStatusItemType")
Planning time: 0.915 ms
Execution time: 0.100 ms
Тогда, когда данные вставляются, это становится действительно плохим планом. 474мс в этом примере. Он должен выполняться тысячи раз в зависимости от того, что загружено, поэтому 474 мс - это плохо.
Aggregate (cost=16.44..16.45 rows=1 width=4) (actual time=474.222..474.222 rows=1 loops=1)
-> Nested Loop (cost=0.57..16.44 rows=1 width=4) (actual time=474.218..474.218 rows=0 loops=1)
Join Filter: ((eh."transactionNumber")::text = (ed."transactionNumber")::text)
-> Index Scan using transaction_pkey on transaction eh (cost=0.29..8.11 rows=1 width=9) (actual time=0.023..0.408 rows=507 loops=1)
Index Cond: (("businessIdentifier")::text = '37'::text)
Filter: ("transactionStatus" = 'posted'::"transactionStatusItemType")
-> Index Scan using transactionlineprovdateindex on "transactionLine" ed (cost=0.29..8.31 rows=1 width=5) (actual time=0.934..0.934 rows=0 loops=507)
Index Cond: (("businessIdentifier")::text = '37'::text)
Filter: ("reconciliationNumber" = 4519)
Rows Removed by Filter: 2520
Planning time: 0.848 ms
Execution time: 474.278 ms
Вакуумный анализ исправляет это. Но вы не можете запустить анализ вакуума, пока транзакция не будет завершена. После Вакуумного анализа postgresql использует другой план и возвращается к 0,1 мс.
Aggregate (cost=16.63..16.64 rows=1 width=4) (actual time=0.072..0.072 rows=1 loops=1)
-> Nested Loop (cost=0.57..16.63 rows=1 width=4) (actual time=0.069..0.069 rows=0 loops=1)
-> Index Scan using transactionlinedateindex on "transactionLine" ed (cost=0.29..8.31 rows=1 width=5) (actual time=0.067..0.067 rows=0 loops=1)
Index Cond: ((("businessIdentifier")::text = '37'::text) AND ("reconciliationNumber" = 4519))
-> Index Scan using transaction_pkey on transaction eh (cost=0.29..8.31 rows=1 width=9) (never executed)
Index Cond: ((("businessIdentifier")::text = '37'::text) AND (("transactionNumber")::text = (ed."transactionNumber")::text))
Filter: ("transactionStatus" = 'posted'::"transactionStatusItemType")
Planning time: 1.134 ms
Execution time: 0.141 ms
Моя работа заключается в том, чтобы выполнить коммит после примерно 100 вставок, а затем запустить анализ вакуума и затем продолжить. Единственная проблема заключается в том, что если что-то в оставшейся части данных завершится неудачно и будет выполнен откат, все равно будет вставлено 100 записей.
Есть ли лучший способ справиться с этим? Должен ли я просто обновиться до версии 10 или 11 или postgresql, и это поможет?