У меня есть приложение, которое должно загружать данные из заданных пользователем CSV-файлов в таблицы базы данных PostgreSQL.Загрузить данные из CSV-файла в базу данных PostgreSQL
Структура CSV-файл очень прост:
name,email
John Doe,[email protected]
...
В базе данных у меня есть три таблицы:
---------------
-- CAMPAIGNS --
---------------
CREATE TABLE "campaigns" (
"id" serial PRIMARY KEY,
"name" citext UNIQUE CHECK ("name" ~ '^[-a-z0-9_]+$'),
"title" text
);
----------------
-- RECIPIENTS --
----------------
CREATE TABLE "recipients" (
"id" serial PRIMARY KEY,
"email" citext UNIQUE CHECK (length("email") <= 254),
"name" text
);
-----------------
-- SUBMISSIONS --
-----------------
CREATE TYPE "enum_submissions_status" AS ENUM (
'WAITING',
'SENT',
'FAILED'
);
CREATE TABLE "submissions" (
"id" serial PRIMARY KEY,
"campaignId" integer REFERENCES "campaigns" ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
"recipientId" integer REFERENCES "recipients" ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
"status" "enum_submissions_status" DEFAULT 'WAITING',
"sentAt" timestamp with time zone
);
CREATE UNIQUE INDEX "submissions_unique" ON "submissions" ("campaignId", "recipientId");
CREATE INDEX "submissions_recipient_id_index" ON "submissions" ("recipientId");
Я хочу, чтобы прочитать все строки из указанного CSV-файл и сделать что соответствующие записи существуют в таблицах recipients
и submissions
.
Каким будет наиболее эффективный метод загрузки данных в эти таблицы?
Это, прежде всего, концептуальный вопрос, я не прошу конкретной реализации.
Прежде всего, я наивно пытался читать и анализировать CSV-файл строка за строкой и выдачи
SELECT/INSERT
запросов для каждого E-Mail. Очевидно, это было очень медленное решение, которое позволяло мне загружать ~ 4 тыс. Записей в минуту, но код был довольно простым и простым.Теперь я читаю CSV-файл по строкам, но объединяю все электронные письма в партии из 1 000 элементов. Все запросы
SELECT/INSERT
производятся партиями с использованием конструкцийSELECT id, email WHERE email IN ('...', '...', '...', ...)
. Такой подход повысил производительность, и теперь у меня производительность ~ 25 тыс. Записей в минуту. Однако для этого подхода потребовался довольно сложный многоэтапный код.
Есть ли какие-либо более эффективные подходы к решению этой проблемы и получить еще большую производительность?
Основной проблемой здесь является то, что мне нужно вставить данные в таблицу recipients
первой, а затем мне нужно использовать сгенерированный id
создать соответствующую запись в таблице submissions
.
Кроме того, мне нужно убедиться, что вставленные E-Mail уникальны. Прямо сейчас, я использую простой индекс на основе массива в своем приложении, чтобы предотвратить добавление дубликатов E-Mails в пакет.
Я пишу свое приложение, используя Node.js
и Sequelize
с Knex
, однако конкретная технология здесь не имеет значения.
Загрузка данных в временную таблицу, а затем использовать любую функцию из SQL/PostgreSQL, что вам необходимо. – Abelisto
Вы знакомы с командой COPY (http://www.postgresql.org/docs/9.5/static/sql-copy.html)? Переведите его во временную таблицу, а затем используйте свои вставки для заполнения таблиц назначения.(COPY не является стандартным SQL btw) –
Использование 'COPY' - это самый быстрый способ. Смотрите: http://stackoverflow.com/questions/33271377/postgres-csv-copy-from-import-is-not-respecting-csv-headers –