Câu trả lời:
PostgreSQL có một hướng dẫn về cách tạo cơ sở dữ liệu tốt nhất ban đầu và họ đề nghị sử dụng lệnh COPY cho các hàng tải hàng loạt. Hướng dẫn có một số mẹo hay khác về cách tăng tốc quá trình, như xóa chỉ mục và khóa ngoại trước khi tải dữ liệu (và thêm lại chúng sau đó).
Có một cách khác để sử dụng COPY, đó là cú pháp giá trị đa hướng mà Postgres hỗ trợ. Từ tài liệu :
INSERT INTO films (code, title, did, date_prod, kind) VALUES
('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');
Đoạn mã trên chèn hai hàng, nhưng bạn có thể mở rộng tùy ý, cho đến khi bạn đạt được số lượng mã thông báo đã chuẩn bị tối đa (có thể là $ 999, nhưng tôi không chắc chắn 100% về điều đó). Đôi khi người ta không thể sử dụng COPY và đây là sự thay thế xứng đáng cho những tình huống đó.
Một cách để tăng tốc mọi thứ là thực hiện rõ ràng nhiều lần chèn hoặc sao chép trong một giao dịch (giả sử 1000). Hành vi mặc định của Postgres là cam kết sau mỗi câu lệnh, vì vậy bằng cách gộp các cam kết, bạn có thể tránh được một số chi phí. Như hướng dẫn trong câu trả lời của Daniel nói, bạn có thể phải tắt chế độ tự động để điều này hoạt động. Cũng lưu ý nhận xét ở phía dưới cho thấy việc tăng kích thước của wal_buffers lên 16 MB cũng có thể giúp ích.
UNNEST
chức năng với các mảng có thể được sử dụng cùng với cú pháp nhiều giá trị. Tôi nghĩ rằng phương pháp này chậm hơn so với sử dụng COPY
nhưng nó hữu ích với tôi khi làm việc với psycopg và python (python list
được truyền để cursor.execute
trở thành pg ARRAY
):
INSERT INTO tablename (fieldname1, fieldname2, fieldname3)
VALUES (
UNNEST(ARRAY[1, 2, 3]),
UNNEST(ARRAY[100, 200, 300]),
UNNEST(ARRAY['a', 'b', 'c'])
);
không VALUES
sử dụng subselect với kiểm tra tồn tại bổ sung:
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
);
cú pháp tương tự để cập nhật hàng loạt:
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;
Bạn có thể sử dụng COPY table TO ... WITH BINARY
" nhanh hơn một chút so với định dạng văn bản và CSV ". Chỉ làm điều này nếu bạn có hàng triệu hàng để chèn và nếu bạn cảm thấy thoải mái với dữ liệu nhị phân.
Dưới đây là một công thức ví dụ trong Python, sử dụng psycopg2 với đầu vào nhị phân .
Nó chủ yếu phụ thuộc vào hoạt động (khác) trong cơ sở dữ liệu. Các hoạt động như thế này có hiệu quả đóng băng toàn bộ cơ sở dữ liệu cho các phiên khác. Một xem xét khác là datamodel và sự hiện diện của các ràng buộc, kích hoạt, vv
Cách tiếp cận đầu tiên của tôi luôn là: tạo bảng (temp) có cấu trúc tương tự bảng mục tiêu (tạo bảng tmp NHƯ chọn * từ mục tiêu trong đó 1 = 0) và bắt đầu bằng cách đọc tệp vào bảng tạm thời. Sau đó, tôi kiểm tra những gì có thể được kiểm tra: trùng lặp, khóa đã tồn tại trong mục tiêu, v.v.
Sau đó, tôi chỉ cần thực hiện "làm chèn vào mục tiêu chọn * từ tmp" hoặc tương tự.
Nếu điều này không thành công hoặc mất quá nhiều thời gian, tôi hủy bỏ nó và xem xét các phương pháp khác (tạm thời bỏ chỉ mục / ràng buộc, v.v.)
Tôi đã triển khai trình tải dữ liệu Postgresq rất nhanh với các phương thức libpq riêng. Hãy thử gói của tôi https://www.nuget.org/packages/NpgsqlBulkCopy/
Tôi vừa gặp phải vấn đề này và muốn giới thiệu csvsql ( bản phát hành ) cho nhập hàng loạt vào Postgres. Để thực hiện chèn hàng loạt, bạn chỉ cần createdb
sử dụng csvsql
, sau đó kết nối với cơ sở dữ liệu của bạn và tạo các bảng riêng lẻ cho toàn bộ thư mục CSV.
$ createdb test
$ csvsql --db postgresql:///test --insert examples/*.csv
Thuật ngữ "dữ liệu số lượng lớn" có liên quan đến "rất nhiều dữ liệu", do đó, việc sử dụng dữ liệu thô ban đầu là điều tự nhiên , không cần phải chuyển đổi thành SQL. Các tệp dữ liệu thô điển hình cho "chèn số lượng lớn" là các định dạng CSV và JSON .
Trong các ứng dụng ETL và quy trình nhập dữ liệu, chúng ta cần thay đổi dữ liệu trước khi chèn nó. Bảng tạm thời tiêu tốn (rất nhiều) dung lượng đĩa và đó không phải là cách nhanh hơn để làm điều đó. Trình bao bọc dữ liệu nước ngoài PostgreSQL (FDW) là lựa chọn tốt nhất.
Ví dụ CSV . Giả sử tablename (x, y, z)
trên SQL và một tệp CSV như
fieldname1,fieldname2,fieldname3
etc,etc,etc
... million lines ...
Bạn có thể sử dụng SQL cổ điển COPY
để tải ( như dữ liệu gốc) tmp_tablename
, họ chèn dữ liệu đã lọc vào tablename
... Nhưng, để tránh tiêu thụ đĩa, cách tốt nhất là nhập trực tiếp vào
INSERT INTO tablename (x, y, z)
SELECT f1(fieldname1), f2(fieldname2), f3(fieldname3) -- the transforms
FROM tmp_tablename_fdw
-- WHERE condictions
;
Bạn cần chuẩn bị cơ sở dữ liệu cho FDW và thay vào đó, tmp_tablename_fdw
bạn có thể sử dụng hàm tạo ra nó :
CREATE EXTENSION file_fdw;
CREATE SERVER import FOREIGN DATA WRAPPER file_fdw;
CREATE FOREIGN TABLE tmp_tablename_fdw(
...
) SERVER import OPTIONS ( filename '/tmp/pg_io/file.csv', format 'csv');
Ví dụ JSON . Một bộ gồm hai tệp myRawData1.json
và Ranger_Policies2.json
có thể được nhập bằng cách:
INSERT INTO tablename (fname, metadata, content)
SELECT fname, meta, j -- do any data transformation here
FROM jsonb_read_files('myRawData%.json')
-- WHERE any_condiction_here
;
trong đó hàm jsonb_read_files () đọc tất cả các tệp của thư mục, được xác định bởi mặt nạ:
CREATE or replace FUNCTION jsonb_read_files(
p_flike text, p_fpath text DEFAULT '/tmp/pg_io/'
) RETURNS TABLE (fid int, fname text, fmeta jsonb, j jsonb) AS $f$
WITH t AS (
SELECT (row_number() OVER ())::int id,
f as fname,
p_fpath ||'/'|| f as f
FROM pg_ls_dir(p_fpath) t(f)
WHERE f like p_flike
) SELECT id, fname,
to_jsonb( pg_stat_file(f) ) || jsonb_build_object('fpath',p_fpath),
pg_read_file(f)::jsonb
FROM t
$f$ LANGUAGE SQL IMMUTABLE;
Phương pháp phổ biến nhất cho "nhập tệp" (chủ yếu trong Dữ liệu lớn) là bảo toàn tệp gốc ở định dạng gzip và chuyển nó bằng thuật toán phát trực tuyến , bất cứ thứ gì có thể chạy nhanh và không tiêu thụ đĩa trong các ống unix:
gunzip remote_or_local_file.csv.gz | convert_to_sql | psql
Vì vậy, lý tưởng (tương lai) là một tùy chọn máy chủ cho định dạng .csv.gz
.