PostgreSQL에서 대량 로드 속도 향상

PostgreSQL에서 대량 로드 속도 향상



PostgreSQL에 데이터를 대량 로드하는 4가지 방법 테스트

속도의 필요성



수백 개의 레코드만 데이터베이스에 로드해야 하는 경우에는 효율성에 대해 크게 걱정하지 않을 수 있습니다. 그러나 수천 또는 수백만 개의 레코드를 삽입하려고 하면 어떻게 됩니까? 이제 데이터 로딩 효율성은 프로젝트의 성공과 실패의 차이를 의미할 수 있으며, 적어도 적시에 제공되는 프로젝트와 심하게 기한이 지난 프로젝트의 차이를 의미할 수 있습니다.

PostgreSQL에는 이 작업에 최적화된 훌륭한 복사 명령이 있습니다: https://www.postgresql.org/docs/current/sql-copy.html . 그러나 이는 데이터가 구체적으로 CSV(또는 이진) 파일에 있는 경우에만 좋은 솔루션입니다. 하지만 순수한 SQL에서 데이터를 로드해야 한다면 어떻게 해야 할까요? 그럼 가장 빠른 방법은?

데이터를 삽입하는 네 가지 방법



기본 삽입 명령



몇 가지 기본 SQL 삽입 명령의 구조를 살펴보겠습니다.

create table users (id integer, firstname text, lastname text);
insert into users (id, firstname, lastname) values (1, 'George', 'Washington');
insert into users (id, firstname, lastname) values (2, 'John', 'Adams');
insert into users (id, firstname, lastname) values (3, 'Thomas', 'Jefferson');


이제 사용자 테이블에 레코드를 삽입하기 위한 몇 가지 기본 SQL이 있습니다. 이렇게 하면 데이터를 테이블로 가져올 수 있지만 데이터를 테이블로 가져오는 가장 느린 방법입니다. 속도를 높일 수 있는 몇 가지 방법을 살펴보겠습니다.

업무



작업 속도를 높이는 빠르고 쉬운 방법은 단순히 대량의 insert 문 배치를 트랜잭션 내부에 넣는 것입니다.

begin transaction;
insert into users (id, firstname, lastname) values (1, 'George', 'Washington');
insert into users (id, firstname, lastname) values (2, 'John', 'Adams');
insert into users (id, firstname, lastname) values (3, 'Thomas', 'Jefferson');
commit;


내 Windows 테스트에서 이것은 100k 사용자 레코드 삽입 속도를 두 배로 늘렸습니다. MacOS에서는 속도가 3배 증가했습니다. 기술적으로는 수십억 개의 레코드가 포함된 배치를 생성할 수 있지만 하드웨어, 대역폭 및 레코드를 기반으로 가장 잘 작동하는 것을 확인하기 위해 1000, 10000, 100000 등의 배치 크기로 실험하고 싶을 것입니다. 크기.

일괄 삽입



작업 속도를 높이는 또 다른 방법은 삽입을 수행할 때 SQL 배치 삽입 구문을 사용하는 것입니다. 예를 들어:

insert into users (id, firstname, lastname) values 
  (1, 'George', 'Washington'),
  (2, 'John', 'Adams'),
  (3, 'Thomas', 'Jefferson');


이 방법을 사용하면 작업 속도가 상당히 빨라집니다. 내 테스트에서는 약 6배 더 빨랐습니다. 동일한 규칙이 트랜잭션과 마찬가지로 배치 크기에 적용됩니다. 여러 배치 크기를 테스트하여 최적화할 수 있습니다. 나는 일반적으로 대부분의 응용 프로그램에 대해 약 10000개의 레코드 배치로 시작하는 경향이 있으며 그것이 충분히 잘 작동하면 그대로 둡니다.

둘 다 어때?



더 빠른 속도를 위해 트랜잭션과 일괄 삽입 문을 결합할 수 있습니까? 글쎄, 예, 아니오. 확실히 그것들을 결합할 수는 있지만 속도 증가는 미미합니다(또는 내 Windows 테스트 사례에서는 속도가 약간 느려졌습니다.)

begin transaction;
insert into users (id, firstname, lastname) values 
  (1, 'George', 'Washington'),
  (2, 'John', 'Adams'),
  (3, 'Thomas', 'Jefferson');
commit;


따라서 여기에서 두 기술을 모두 사용하는 것이 완벽하게 유효하지만 데이터를 로드하는 가장 빠른 방법은 아닐 수 있습니다.

단점



트랜잭션 또는 배치 삽입을 사용할 때 잠재적인 단점은 무엇입니까? 오류 처리가 주요한 것입니다. 배치의 레코드 중 하나라도 실패하면 전체 배치가 실패하고 해당 배치에서 테이블에 데이터가 삽입되지 않습니다. 따라서 데이터가 유효한지 또는 실패한 배치를 분해하고 수정할 수 있는 방법이 있는지 확인해야 합니다.

고유 제약 조건으로 인해 실패가 발생한 경우 삽입 문에 on conflict 절을 사용할 수 있지만 다른 이유로 삽입이 실패하면 전체 배치가 삭제됩니다.

기타 속도 고려 사항



데이터 삽입 속도에 영향을 미칠 수 있는 다른 많은 요소와 작업을 더 빠르게 할 수 있는 방법이 있습니다. 데이터를 삽입할 때까지 인덱스를 제거하고, 로그되지 않은 테이블을 만들고, 불필요한 고유 키를 피하는 것은 이 중 일부에 불과합니다. 이러한 다른 최적화는 성능을 향상시키지만 여기에 설명된 기본 기술만큼 극적으로 향상되지는 않을 것입니다.

결론



많은 양의 데이터를 처리해야 하는 경우 SQL 삽입 코드를 작성할 때 미리 계획하는 것이 좋습니다. 몇 가지 작은 변경으로 잠재적으로 처리 시간을 몇 시간(때로는 며칠)까지 절약할 수 있습니다.

부록: 샘플 테스트 결과



이러한 메서드를 테스트하는 일부 코드는 내 GitHub Repopostgresql-bulk-load-tests를 참조하십시오. 내 테스트 실행 결과는 다음과 같습니다.



===========================
Windows VM (UTM Windows 11)
===========================
create 100k users with individual insert statements
30.0 seconds
create 100k users with individual insert statements in a transaction
14.0 seconds
create 100k users with batch insert statement
4.3 seconds
create 100k users with batch insert statement in a transaction
4.6 seconds

====================
MacBook Pro (M1 Max)
====================
create 100k users with individual insert statements

real    0m9.112s
user    0m0.509s
sys     0m0.337s

create 100k users with individual insert statements in a transaction

real    0m2.540s
user    0m0.457s
sys     0m0.325s

create 100k users with batch insert statement

real    0m1.360s
user    0m0.179s
sys     0m0.042s

create 100k users with batch insert statement in a transaction

real    0m1.154s
user    0m0.189s
sys     0m0.041s

좋은 웹페이지 즐겨찾기