PostgreSQL에서 한 테이블에서 다른 테이블로 수백만 행을 효율적으로 복사하는 방법은 무엇입니까?


36

두 개의 데이터베이스 테이블이 있습니다. 하나는 수억 개의 레코드를 포함합니다. 그 하나를 부를 수 history있습니다. 다른 하나는 매일 계산되며 모든 레코드를 history하나 에 복사하고 싶습니다 .

내가 한 일은 달렸다.

INSERT INTO history SELECT * FROM daily

그리고 한동안 트릭을 수행했지만 레코드 수가 계속 증가함에 따라 점점 느려졌습니다. 지금은 복사 할 필요가 약 200 만 기록을 가지고 dailyhistory단일 작업을하고 그것을 완료하는 데 시간이 오래 걸립니다.

한 테이블에서 다른 테이블로 데이터를 복사하는 또 다른보다 효율적인 방법이 있습니까?

답변:


10

오랜 기간 (수개월) 동안 기록을 유지하려는 경우 분할 옵션을 살펴 보는 것이 좋습니다. 매일 또는 매주 한 파티션이 될 수 있습니다. 그것은 당신의 기록 테이블의 액세스 패턴에 달려 있습니다 (날짜에 걸쳐 데이터에 액세스하는 쿼리를 실행합니까? 많은 집계를 수행합니까). 집계 / 요약을 저장하기위한 구체화 된보기를 살펴보십시오. http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html http://www.postgresql.org/docs/9.3/static/sql-creatematerializedview.html


답변 해주셔서 감사합니다. 가는 유일한 길인 것 같습니다. 데이터를 몇 개월 단위로 분할해야하므로 인덱스 재생성 (여기서 색인 재생성 문제이므로)을 훨씬 빠르게 수행해야합니다.
Milovan Zogovic

16

CSV 형식으로 테이블 덤프

COPY table TO '/tmp/table.csv' DELIMITER ',';

대량의 데이터에 훨씬 효율적인 COPY 명령을 사용하십시오.

COPY table FROM '/tmp/table.csv' DELIMITER ',';

자세한 내용 은 http://www.postgresql.org/docs/current/static/sql-copy.html 에서 postgres 문서를 확인하십시오.


1
여전히 매우 느리게 실행되고 있습니다. 아마도 그런 거대한 인덱스를 다시 작성해야 할 일이 있습니까? history테이블 에는 1 억 6 천만 행이 있으며 3 백만 행이 추가됩니다.
Milovan Zogovic

2
빈 테이블을 가득 채우거나 이미 존재하는 것보다 많은 행을 추가하는 경우, 일반적으로 비 클러스터형 인덱스를 삭제하고 전송이 완료된 후 다시 생성하는 것이 더 효율적입니다 (테이블이 활성 상태가 아닌 한) )
David Spillett

BTW, 이것은 일회성 작업입니까, 아니면 정기적으로해야합니까? 정기적으로 트리거를 생성한다고 제안하면 매번이 시련을 겪을 필요가 없습니다.
Fabrizio Mazzoni

@FabrizioMazzoni-특정 시간에 매일 수행해야합니다 (시간에 따라 스냅 샷 작성).
Milovan Zogovic

@DavidSpillett-참으로! (I 데이터베이스에서 160M 행이 있기 때문에) 인덱스 차종 (위 내 대답을 참조) 매우 빠른 가져 삭제하지만, 인덱스를 다시하는 것은 .. 시간이 소요
Milovan Zogovic에게

13

문제는 색인에있었습니다. 이 history테이블에는 160M 개의 인덱스 행이 있습니다. 중 하나를 실행하여 COPY FROM또는 INSERT INTO .. SELECT이 있지만 업데이트 인덱스에 행을 삽입 할 수없는 많은 시간을 복용했다. 인덱스를 비활성화하면 10 초 안에 3M 행을 가져 왔습니다. 이제 큰 테이블을 다시 색인화하는 더 빠른 방법을 찾아야합니다.


3
히스토리 테이블에 인덱스가 필요합니까?
Sherlock

2
CONCURRENTLY 키워드를 사용하여 색인 추가
Akvel

10

psql 도구 를 사용할 수 있습니다 . 다음과 같이 효율적일 수 있습니다.

psql -h ${DAILY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"

또한 쉘 스크립트를 작성할 수 있습니다.


중간 파일이없는 훌륭한 솔루션. 매우 빠릅니다. 나는 일반 디스크와 네트워크 파일 시스템 사이에서 1 시간 20 분 (인덱스 제외)에 9 억 5 천만 행 테이블을 복사했습니다.
르 드로이드

3

이것은 물론 질문에 대한 정확한 대답은 아니지만 history테이블 에 액세스 할 필요가 없으면 SQL 덤프를 생성 할 수도 있습니다.

pg_dump -h host -p port -w -U user db > dump.sql

그런 다음 git차이를 계산하고이를 효율적으로 저장하는 것과 같은 도구를 사용할 수 있습니다 .

git add dump.sql
git commit -m "temp dump"
git gc --aggressive

데이터베이스의 대부분의 부분이 매일 변경되지 않으므로 유용합니다. 매일 전체 사본을 저장하는 대신 이틀 간의 차이를 저장할 수 있습니다.

crontab덤프가 매일 처리되도록 작업을 사용할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.