Yanıtlar:
PostgreSQL, başlangıçta bir veritabanının en iyi nasıl yerleştirileceği konusunda bir kılavuza sahiptir ve toplu yükleme satırları için COPY komutunu kullanmanızı önerir . Kılavuz, verileri yüklemeden önce dizinleri ve yabancı anahtarları kaldırmak (ve daha sonra bunları geri eklemek) gibi işlemin nasıl hızlandırılacağıyla ilgili başka iyi ipuçlarına sahiptir.
Postgres'in desteklediği çok satırlı değerler sözdizimi olan COPY'yi kullanmanın bir alternatifi vardır. Gönderen belgeler :
INSERT INTO films (code, title, did, date_prod, kind) VALUES
('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');
Yukarıdaki kod iki satır ekler, ancak hazırlanan deyim jetonlarının maksimum sayısına ulaşana kadar keyfi olarak genişletebilirsiniz (999 $ olabilir, ancak bundan% 100 emin değilim). Bazen COPY kullanılamaz ve bu durumların yerini almaya değer.
İşleri hızlandırmanın bir yolu, bir işlem içinde açıkça birden fazla ek veya kopya gerçekleştirmektir (örneğin 1000). Postgres'in varsayılan davranışı her ifadeden sonra işlem yapmaktır, bu nedenle taahhütleri toplu hale getirerek bazı ek yükleri önleyebilirsiniz. Daniel'in cevabındaki kılavuzda belirtildiği gibi, bunun çalışması için otomatik taahhüdü devre dışı bırakmanız gerekebilir. Ayrıca, wal_buffers'ın boyutunu 16 MB'a çıkarmayı öneren altta yer alan yorumun da yardımcı olabileceğini unutmayın.
UNNEST
dizilerle işlev, çok satırlı VALUES sözdizimi ile birlikte kullanılabilir. Bu yöntem kullanmaktan daha yavaş olduğunu düşünüyorum COPY
ama psycopg ve python (python list
geçti cursor.execute
pg ARRAY
) ile çalışmalarında benim için yararlı :
INSERT INTO tablename (fieldname1, fieldname2, fieldname3)
VALUES (
UNNEST(ARRAY[1, 2, 3]),
UNNEST(ARRAY[100, 200, 300]),
UNNEST(ARRAY['a', 'b', 'c'])
);
olmadan VALUES
ek varlığı çek ile Alt Seç'i kullanarak:
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
);
toplu güncellemelerle aynı sözdizimi:
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;
COPY table TO ... WITH BINARY
" Metin ve CSV biçimlerinden biraz daha hızlı " olanı kullanabilirsiniz . Bunu yalnızca, eklemek için milyonlarca satırınız varsa ve ikili verilerden memnunsanız yapın.
İşte ikili girişli psycopg2 kullanan Python'da bir örnek tarif .
Çoğunlukla veritabanındaki (diğer) etkinliğe bağlıdır. Bunun gibi işlemler, diğer oturumlar için tüm veritabanını etkili bir şekilde dondurur. Başka bir husus, veri modeli ve kısıtlamaların, tetikleyicilerin vb.
İlk yaklaşımım her zaman: hedef tabloya benzer bir yapıya sahip bir (temp) tablo oluşturmak (1 = 0 olan hedeften tablo tmp AS select * oluştur) ve dosyayı geçici tabloya okuyarak başlayın. Sonra neyin kontrol edilebileceğini kontrol ediyorum: kopyalar, hedefte zaten var olan anahtarlar, vb.
Sonra ben sadece "tmp from target select * eklemek" veya benzeri yapmak.
Bu başarısız olursa veya çok uzun sürerse, iptal ediyorum ve diğer yöntemleri (geçici olarak dizinleri / kısıtlamaları vb.
Yerel libpq yöntemleriyle çok hızlı Postgresq veri yükleyicisi uyguladım. Paketimi dene https://www.nuget.org/packages/NpgsqlBulkCopy/
Ben sadece bu sorunla karşılaştı ve Postgres toplu ithalat için csvsql ( bültenleri ) tavsiye ederim . Toplu bir ekleme yapmak için, veritabanınıza bağlanan ve tüm CSV klasörleri için ayrı ayrı tablolar oluşturan basit createdb
ve daha sonra kullanabilirsiniz csvsql
.
$ createdb test
$ csvsql --db postgresql:///test --insert examples/*.csv
"Toplu veri" terimi "çok fazla veri" ile ilgilidir, bu nedenle orijinal ham verilerin SQL'e dönüştürülmesine gerek kalmadan kullanılması doğaldır . "Toplu ekleme" için tipik ham veri dosyaları CSV ve JSON formatlarıdır.
Gelen ETL uygulamaları ve yutma süreçler, bunu takmadan önce verileri değiştirmek gerekir. Geçici tablo (çok fazla) disk alanı tüketir ve bunu yapmanın daha hızlı yolu değildir. PostgreSQL yabancı veri sarıcı (FDW) en iyi seçimdir.
CSV örneği . Varsayalım tablename (x, y, z)
SQL ve bir CSV dosyası gibi üzerinde
fieldname1,fieldname2,fieldname3
etc,etc,etc
... million lines ...
Sen klasik SQL kullanabilirsiniz COPY
(yüke olduğu gibi orijinal veri) tmp_tablename
içine, onları filtreden insert veri tablename
önlemek diski tüketimine ... Ama iyi tarafından doğrudan ağızdan etmektir
INSERT INTO tablename (x, y, z)
SELECT f1(fieldname1), f2(fieldname2), f3(fieldname3) -- the transforms
FROM tmp_tablename_fdw
-- WHERE condictions
;
FDW için veritabanı hazırlamanız gerekir ve bunun yerine statik tmp_tablename_fdw
, onu üreten bir işlevi kullanabilirsiniz :
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');
JSON örneği . Bir dizi iki dosya myRawData1.json
ve Ranger_Policies2.json
tarafından alınabilir:
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
;
burada jsonb_read_files () işlevi , bir klasörün maske tarafından tanımlanan tüm dosyalarını okur:
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;
"Dosya alımı" için en sık kullanılan yöntem (esas olarak Büyük Veri'de) orijinal dosyayı gzip biçiminde korumak ve dosyayı unix borularda hızlı ve disk tüketimi olmadan çalışabilen akış algoritmasıyla aktarmaktır :
gunzip remote_or_local_file.csv.gz | convert_to_sql | psql
Yani ideal (gelecek) format için bir sunucu seçeneğidir.csv.gz
.