我有一個應用程序,需要將用戶指定的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
查詢每個電子郵件。顯然,這是一個非常緩慢的解決方案,它允許我每分鐘加載約4k條記錄,但代碼非常簡單明瞭。現在,我正在逐行讀取CSV文件,但將所有電子郵件彙總爲1'000個元素的批次。所有
SELECT/INSERT
查詢是使用SELECT id, email WHERE email IN ('...', '...', '...', ...)
構造分批進行的。這種方法提高了性能,現在我的性能達到了每分鐘25k的記錄。但是,這種方法需要一個非常複雜的多步代碼才能工作。
有沒有更好的方法來解決這個問題,並獲得更高的性能?
這裏的關鍵問題是,我需要首先將數據插入到recipients
表,然後我需要使用產生id
在submissions
表中創建一個相應的記錄。
此外,我需要確保插入的電子郵件是唯一的。現在,我在我的應用程序中使用了一個簡單的基於數組的索引,以防止重複的電子郵件被添加到批處理中。
我正在使用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 –