데이터베이스의 네이티브 bulk-load 경로(Postgres COPY, MySQL LOAD DATA)를 사용하고, 파일을 청크로 나눠 인덱스와 제약을 한 로 로드한 뒤, 인덱스를 한 번에 재구축하고 병합하십시오 — 그리고 crash가 row를 중복 없이 재개할 수 있도록 전체 job을 하게 만드십시오.
100M-row CSV
│ split by byte offset
▼
[chunk 1] [chunk 2] ... [chunk N] N parallel workers
│ │ │
└──── COPY / LOAD DATA (no indexes) ────▶ staging_table (UNLOGGED)
│
rebuild indexes + validate
│
INSERT ... SELECT (upsert) into target
순진한 row당 INSERT는 왕복, 파싱, WAL/redo write, 인덱스 업데이트를 1억 번 치릅니다. 각각 1ms만 잡아도 하루가 넘습니다. bulk 경로는 이 모두를 분할 상환하여 이깁니다: COPY는 row를 하나의 프로토콜 메시지로 스트리밍하고, WAL을 batch하며, 문장별 planning을 건너뜁니다. 실제 하드웨어에서 단일 COPY는 초당 10만~50만 row를 처리하는 반면 INSERT는 몇 천에 그칩니다.
UNLOGGED는 WAL을 완전히 건너뜀)로 로드하고, 절대 라이브 테이블로 곧장 로드하지 마십시오. 이는 로드를 reader로부터 격리하고, 게시(publish) 전에 검증할 수 있게 합니다.CREATE INDEX를 한 번 하십시오 — 인덱스를 bulk로(정렬된 상태로) 빌드하는 것이 1억 번의 증분 업데이트보다 훨씬 저렴합니다.COPY 스트림을 실행하십시오. throughput은 디스크나 WAL을 포화시킬 때까지 I/O와 CPU에 따라 확장됩니다. N을 "가능한 한 많이"가 아니라 코어/IOPS에 맞추십시오.INSERT ... ON CONFLICT DO NOTHING/UPDATE(upsert)로 게시하여 재실행이 절대 이중 삽입하지 않게 하십시오.면접관은 당신이 bulk 경로가 존재함과 왜 수십 배 빠른지를 아는지 확인하는 것이지, COPY 문법이 아닙니다. 좋은 답변: "COPY를 쓴다." 훌륭한 답변: "UNLOGGED staging 테이블로 COPY, 인덱스 드롭, 병렬 청크, 이후 재구축, upsert로 게시, 청크 id로 재개 가능." 전형적인 함정은 INSERT를 루프(또는 ORM saveAll)하고 몇 시간이 걸린다는 데 놀라는 것이고, 두 번째 함정은 라이브 테이블로 곧장 로드하여 프로덕션을 막는 것입니다.
maintenance_work_mem/임시 공간이 필요합니다. 1억 row 인덱스 빌드는 디스크로 spill될 수 있습니다.주니어부터 시니어까지 상세한 답변이 포함된 IT 면접 질문 라이브러리.
후원하기