Работа с приложением и обработка каждой отдельной строки много медленная загрузка данных непосредственно на сервер. Даже с оптимизированным кодом. Кроме того, вставка / обновление по одной строке за раз намного медленнее, чем обработка всего за один раз.
Если файлы импорта доступны локально для сервера, вы можете использовать COPY
. В противном случае вы можете использовать мета-команду \copy
в стандартном интерфейсе psql
. Вы упомянули JSON, чтобы это работало, вам необходимо преобразовать данные в подходящий плоский формат, такой как CSV.
Если вы просто хотите добавить новые строки в таблицу:
COPY tbl FROM '/absolute/path/to/file' FORMAT csv;
Или, если вы хотите ВСТАВИТЬ / ОБНОВИТЬ несколько строк:
Прежде всего: используйте достаточно оперативной памяти для temp_buffers (по крайней мере, временно, если можете), чтобы временная таблица не записывалась на диск. Имейте в виду, что это необходимо сделать перед доступом к любым временным таблицам в этом сеансе.
SET LOCAL temp_buffers='128MB';
Представление в памяти занимает несколько больше места, чем представление данных на диске. Таким образом, для файла JSON размером 100 МБ. Минус издержки JSON плюс некоторые издержки Postgres, 128 МБ может быть или не быть достаточным. Но вам не нужно угадывать, просто выполните тестовый прогон и измерьте его:
select pg_size_pretty(pg_total_relation_size('tmp_x'));
Создать временную таблицу:
CREATE TEMP TABLE tmp_x (id int, val_a int, val_b text);
Или, чтобы просто продублировать структуру существующей таблицы:
CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;
Копирование значений (должно занять секунд , а не часов):
COPY tmp_x FROM '/absolute/path/to/file' FORMAT csv;
Оттуда INSERT / UPDATE с простым старым SQL. Поскольку вы планируете сложный запрос, вы можете даже добавить index или два к временной таблице и запустить ANALYZE
:
ANALYZE tmp_x;
Например, чтобы обновить существующие строки, соответствующие id
:
UPDATE tbl
SET col_a = tmp_x.col_a
USING tmp_x
WHERE tbl.id = tmp_x.id;
Наконец, удалите временную таблицу:
DROP TABLE tmp_x;
Или он был автоматически удален в конце сеанса.