[postgresql] Postgres에 대량 삽입하는 가장 빠른 방법은 무엇입니까?

프로그래밍 방식으로 포스트 레코드 데이터베이스에 천만 개의 레코드를 삽입해야합니다. 현재 하나의 “쿼리”에 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 형식보다 다소 빠른 “것을 사용할 수 있습니다 . 삽입 할 행이 수백만 개이고 이진 데이터에 익숙한 경우에만이 작업을 수행하십시오.

다음은 바이너리 입력과 함께 psycopg2를 사용하는 Python예제 레시피입니다 .


답변

주로 데이터베이스의 (기타) 활동에 따라 다릅니다. 이와 같은 작업은 다른 세션을 위해 전체 데이터베이스를 효과적으로 고정시킵니다. 다른 고려 사항은 데이터 모델과 제약 조건, 트리거 등의 존재입니다.

첫 번째 방법은 항상 : 목표 테이블과 비슷한 구조로 (임시) 테이블을 만들고 (테이블 = tmp AS select * from target where 1 = 0) 파일을 임시 테이블로 읽는 것부터 시작하십시오. 그런 다음 확인할 수있는 항목을 확인합니다. 중복, 대상에 이미 존재하는 키 등

그런 다음 “대상 선택 * tmp에서 삽입”또는 이와 유사한 작업을 수행합니다.

이것이 실패하거나 너무 오래 걸리면 중단하고 다른 방법을 고려하십시오 (일시적으로 색인 / 제약 조건 삭제 등).


답변

네이티브 libpq 메소드를 사용하여 매우 빠른 Postgresq 데이터 로더를 구현했습니다. 내 패키지를보십시오 https://www.nuget.org/packages/NpgsqlBulkCopy/