Какой самый быстрый способ сделать массовую вставку в Postgres? - PullRequest
200 голосов
/ 17 апреля 2009

Мне нужно программно вставить десятки миллионов записей в базу данных postgres. В настоящее время я выполняю тысячи операторов вставки в одном «запросе».

Есть ли лучший способ сделать это, какое-то массовое выражение вставки, о котором я не знаю?

Ответы [ 8 ]

182 голосов
/ 17 апреля 2009

PostgreSQL имеет руководство о том, как лучше всего заполнить базу данных изначально, и они предлагают использовать команду COPY для массовой загрузки строк. В руководстве есть и другие полезные советы по ускорению процесса, такие как удаление индексов и внешних ключей перед загрузкой данных (и последующее добавление их обратно).

70 голосов
/ 27 января 2015

Существует альтернатива использованию COPY, которая является синтаксисом многострочных значений, который поддерживает Postgres. Из документации :

INSERT INTO films (code, title, did, date_prod, kind) VALUES
    ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
    ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');

Приведенный выше код вставляет две строки, но вы можете расширять его произвольно, пока не достигнете максимального количества подготовленных токенов операторов (это может быть 999 долларов, но я не уверен на 100% в этом). Иногда нельзя использовать COPY, и это достойная замена для таких ситуаций.

19 голосов
/ 17 апреля 2009

Одним из способов ускорить процесс является явное выполнение нескольких вставок или копий внутри транзакции (скажем, 1000). Поведение Postgres по умолчанию заключается в фиксации после каждого оператора, поэтому, пакетируя коммиты, вы можете избежать некоторых накладных расходов. Как говорится в ответе Даниэля, возможно, вам придется отключить автокоммит, чтобы это работало. Также обратите внимание на комментарий внизу, который предлагает увеличить размер wal_buffers до 16 МБ, также может помочь.

10 голосов
/ 26 июня 2015
Можно использовать функцию

UNNEST с массивами, а также многострочный синтаксис VALUES. Я думаю, что этот метод медленнее, чем использование COPY, но он мне полезен при работе с psycopg и python (python list, переданный в cursor.execute, становится pg ARRAY):

INSERT INTO tablename (fieldname1, fieldname2, fieldname3)
VALUES (
    UNNEST(ARRAY[1, 2, 3]), 
    UNNEST(ARRAY[100, 200, 300]), 
    UNNEST(ARRAY['a', 'b', 'c'])
);

без VALUES с использованием подвыбора с дополнительной проверкой существования:

INSERT INTO tablename (fieldname1, fieldname2, fieldname3)
SELECT * FROM (
    SELECT UNNEST(ARRAY[1, 2, 3]), 
           UNNEST(ARRAY[100, 200, 300]), 
           UNNEST(ARRAY['a', 'b', 'c'])
) AS temptable
WHERE NOT EXISTS (
    SELECT 1 FROM tablename tt
    WHERE tt.fieldname1=temptable.fieldname1
);

тот же синтаксис для массовых обновлений:

UPDATE tablename
SET fieldname1=temptable.data
FROM (
    SELECT UNNEST(ARRAY[1,2]) AS id,
           UNNEST(ARRAY['a', 'b']) AS data
) AS temptable
WHERE tablename.id=temptable.id;
9 голосов
/ 17 ноября 2011

Вы можете использовать COPY table TO ... WITH BINARY, что " несколько быстрее, чем текст и форматы CSV ." Делайте это только в том случае, если у вас есть миллионы строк для вставки и если вы знакомы с двоичными данными.

Вот пример рецепта на Python с использованием psycopg2 с двоичным входом .

7 голосов
/ 03 сентября 2011

Это в основном зависит от (другой) активности в базе данных. Такие операции эффективно замораживают всю базу данных для других сеансов. Еще одним соображением является модель данных и наличие ограничений, триггеров и т. Д.

Мой первый подход всегда: создать (временную) таблицу со структурой, аналогичной целевой таблице (создать таблицу tmp AS select * from target, где 1 = 0), и начать с чтения файла в временную таблицу. Затем я проверяю, что можно проверить: дубликаты, ключи, которые уже существуют в цели, и т. Д.

Затем я просто делаю "вставлять в target select * from tmp" или подобное.

Если это не удается или занимает слишком много времени, я прекращаю его и рассматриваю другие методы (временное удаление индексов / ограничений и т. Д.)

5 голосов
/ 13 августа 2015

Я только что столкнулся с этой проблемой и рекомендую csvsql для массового импорта в Postgres. Чтобы выполнить массовую вставку, достаточно просто createdb, а затем использовать csvsql, который подключается к вашей базе данных и создает отдельные таблицы для всей папки CSV.

$ createdb test 
$ csvsql --db postgresql:///test --insert examples/*.csv
5 голосов
/ 29 августа 2014

Я реализовал очень быстрый загрузчик данных Postgresq с родными методами libpq. Попробуйте мой пакет https://www.nuget.org/packages/NpgsqlBulkCopy/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...