프로그래밍 방식으로 포스트 레코드 데이터베이스에 천만 개의 레코드를 삽입해야합니다. 현재 하나의 "쿼리"에 1000의 insert 문을 실행하고 있습니다.
이 작업을 수행하는 더 좋은 방법이 있습니까, 내가 모르는 대량 삽입 문이 있습니까?
프로그래밍 방식으로 포스트 레코드 데이터베이스에 천만 개의 레코드를 삽입해야합니다. 현재 하나의 "쿼리"에 1000의 insert 문을 실행하고 있습니다.
이 작업을 수행하는 더 좋은 방법이 있습니까, 내가 모르는 대량 삽입 문이 있습니까?
답변:
PostgreSQL에는 처음에 데이터베이스를 가장 잘 채우는 방법에 대한 가이드 가 있으며 대량로드 행에 COPY 명령을 사용하는 것이 좋습니다 . 이 가이드에는 데이터를로드하기 전에 인덱스와 외래 키를 제거하고 나중에 다시 추가하는 등 프로세스 속도를 높이는 방법에 대한 유용한 팁이 있습니다.
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를 사용할 수 없으며 이러한 상황을 대체 할 가치가 있습니다.
작업 속도를 높이는 한 가지 방법은 트랜잭션 내에서 여러 삽입 또는 복사를 명시 적으로 수행하는 것입니다 (예 : 1000). Postgres의 기본 동작은 각 명령문 이후에 커밋하는 것이므로 커밋을 일괄 처리하여 약간의 오버 헤드를 피할 수 있습니다. Daniel의 답변 안내서에 나와 있듯이 자동 커밋을 비활성화해야 작동 할 수 있습니다. 또한 wal_buffers의 크기를 16MB로 늘릴 것을 제안하는 주석도 도움이 될 수 있습니다.
UNNEST
배열이있는 함수는 다중 행 VALUES 구문과 함께 사용할 수 있습니다. 나는이 방법을 사용하는 것보다 느린이라고 생각 해요 COPY
하지만 psycopg와 파이썬과 일에 나에게 유용하다 (파이썬 list
에 전달 된 cursor.execute
페이지가됩니다 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;
COPY table TO ... WITH BINARY
" 텍스트 및 CSV 형식보다 다소 빠른 "것을 사용할 수 있습니다 . 삽입 할 행이 수백만 개이고 이진 데이터에 익숙한 경우에만이 작업을 수행하십시오.
주로 데이터베이스의 (기타) 활동에 따라 다릅니다. 이와 같은 작업은 다른 세션을 위해 전체 데이터베이스를 효과적으로 고정시킵니다. 다른 고려 사항은 데이터 모델과 제약 조건, 트리거 등의 존재입니다.
첫 번째 방법은 항상 : 목표 테이블과 비슷한 구조로 (임시) 테이블을 만들고 (테이블 = tmp AS select * from target where 1 = 0) 파일을 임시 테이블로 읽는 것부터 시작하십시오. 그런 다음 확인할 수있는 항목을 확인합니다. 중복, 대상에 이미 존재하는 키 등
그런 다음 "대상 선택 * tmp에서 삽입"또는 이와 유사한 작업을 수행합니다.
이것이 실패하거나 너무 오래 걸리면 중단하고 다른 방법을 고려하십시오 (일시적으로 색인 / 제약 조건 삭제 등).
네이티브 libpq 메소드를 사용하여 매우 빠른 Postgresq 데이터 로더를 구현했습니다. 내 패키지를보십시오 https://www.nuget.org/packages/NpgsqlBulkCopy/
"대량 데이터"라는 용어는 "많은 데이터"와 관련이 있으므로 원래 원시 데이터 를 사용하는 것이 자연스럽고 SQL로 변환 할 필요가 없습니다. "대량 삽입"에 대한 일반적인 원시 데이터 파일은 CSV 및 JSON 형식입니다.
에서 ETL의 응용 프로그램 및 섭취 프로세스, 우리는 그것을 삽입하기 전에 데이터를 변경해야합니다. 임시 테이블은 (많은) 디스크 공간을 소비하므로 더 빠른 방법은 아닙니다. PostgreSQL의 해외 데이터 래퍼 (FDW)는 최고의 선택입니다.
CSV 예 . tablename (x, y, z)
on SQL과 같은 CSV 파일을 가정하십시오 .
fieldname1,fieldname2,fieldname3
etc,etc,etc
... million lines ...
당신은 고전 SQL 사용할 수 있습니다 COPY
(부하를 그대로 로 원래의 데이터) tmp_tablename
로, 그들을 필터링 된 데이터 삽입 tablename
을 피하기 디스크 소비, ...하지만, 가장은 직접 섭취하는 것입니다
INSERT INTO tablename (x, y, z)
SELECT f1(fieldname1), f2(fieldname2), f3(fieldname3) -- the transforms
FROM tmp_tablename_fdw
-- WHERE condictions
;
FDW를 위해 데이터베이스를 준비해야하며 대신 정적 데이터베이스를 생성하는 함수를tmp_tablename_fdw
사용할 수 있습니다 .
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 예 . 두 파일의 집합, myRawData1.json
및 Ranger_Policies2.json
섭취 할 수있다 :
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
;
여기서 jsonb_read_files () 함수 는 마스크로 정의 된 폴더의 모든 파일을 읽습니다.
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;
"파일 수집"(주로 빅 데이터)에 대한 가장 빈번한 방법은 원본 파일을 gzip 형식으로 보존 하고 하고 유닉스 파이프에서 디스크를 소비하지 않고 빠르게 실행할 수 스트리밍 알고리즘으로 것입니다.
gunzip remote_or_local_file.csv.gz | convert_to_sql | psql
이상적인 (미래)는 format에 대한 서버 옵션 입니다 .csv.gz
.