Я использую стороннюю оболочку данных для перемещения большого куска данных (с очень простым преобразованием даты в одном столбце) в локальную базу данных.Используя курсор Django (потому что мне лень извлекать учетные данные для создания необработанного курсора psycopg2), я делаю запрос такого типа (анонимный и с удалением пары соединений, но в остальном идентичный оригиналу):
cursor.executemany(
sql.SQL(
"""
INSERT INTO local_table (
foreign_key_id,
other_foreign_key_id,
datetime,
comment
)
SELECT other_local_table.id,
%s,
(object_date + to_timestamp(object_time, 'HH24:MI')::time) at time zone '…',
comment
FROM imported_schema.remote_table
JOIN other_local_table ON other_local_table.code = remote_table.code
"""
),
[(dummy_id,)],
)
Тем не менее, локальный Postgres-сервер через некоторое время всегда убивает OOM .Я ожидал, что Postgres сбросит новые строки на диск, чтобы избежать нехватки памяти, но, насколько я могу судить, этого просто не происходит - /var/lib/docker/volumes/vagrant_postgres_data
увеличивается только на несколько МБ, в то время как резидентное использование памяти превращается в ГБ.На локальном сервере недостаточно оперативной памяти для хранения всего набора результатов в памяти, поэтому мне нужно решение, которое не требует более дорогой настройки оборудования.
Нужно ли устанавливать что-то вроде wal_sync_method
илиwork_mem
чтобы это работало?
Согласно документам executemany
должно быть правильным инструментом для работы:
Эта функция в основном полезна для команд, которыеобновите базу данных: любой набор результатов, возвращенный запросом, отбрасывается.
Запуск Postgres 10.6 контейнеров в Linux на обоих серверах и в Django 2.1 локально.Я не использую никаких расширений, кроме FDW.
Объясните план:
Insert on local_table (cost=817872.44..818779.47 rows=25915 width=56)
-> Subquery Scan on "*SELECT*" (cost=817872.44..818779.47 rows=25915 width=56)
-> HashAggregate (cost=817872.44..818390.74 rows=25915 width=48)
Group Key: other_local_table.id, 1, timezone('…'::text, (remote_table.object_date + (to_timestamp((remote_table.object_time)::text, 'HH24:MI'::text))::time without time zone)), remote_table.comment
-> Nested Loop (cost=101.15..807974.88 rows=989756 width=48)
-> Nested Loop (cost=0.57..60.30 rows=73 width=12)
-> Nested Loop (cost=0.29..42.35 rows=38 width=4)
-> Seq Scan on fourth_local_table (cost=0.00..7.45 rows=1 width=4)
Filter: ((code)::text = '…'::text)
-> Index Scan using … on third_local_table (cost=0.29..34.49 rows=41 width=8)
Index Cond: (id = fourth_local_table.id)
-> Index Scan using … on other_local_table (cost=0.29..0.45 rows=2 width=16)
Index Cond: (id = third_local_table.id)
-> Foreign Scan on remote_table (cost=100.58..9421.44 rows=151030 width=20)
postgresqltuner предлагает I
set vm.overcommit_memory = 2 в /etc/sysctl.conf… Это отключит чрезмерное использование памяти и предотвратит уничтожение postgresql убийцей OOM.
Это решение?