postgres에서 행을 대량으로 삭제하는 가장 효율적인 방법


23

PostgreSQL에서 많은 수의 행을 삭제하는 가장 효율적인 방법이 궁금합니다.이 프로세스는 매일 대량의 데이터 (삽입 + 삭제 델타)를 테이블로 가져 오는 반복 작업의 일부입니다. 삭제할 수천 개, 잠재적으로 수백만 개의 행이있을 수 있습니다.

기본 키 파일이 한 줄에 하나씩 있습니다. 내가 생각한 두 가지 옵션은 아래의 내용을 따르지만 PostgreSQL의 내부를 충분히 이해하지 못하여 가장 적합한 결정을 내릴 수 있습니다.

  • 기본 키를 DELETE단순하게 사용하여 파일의 각 행에 대해 쿼리를 실행합니다 WHERE(또는 절 을 n사용하여 일괄 적으로 삭제 그룹화 IN())
  • COPY명령을 사용하여 기본 키를 임시 테이블로 가져온 후 조인을 사용하여 기본 테이블에서 삭제

어떤 제안이라도 대단히 감사하겠습니다!


1
같은 질문이 여기에 더 자세히 설명되어 있습니다 : stackoverflow.com/a/8290958
Simon

답변:


25

두 번째 옵션은 훨씬 깨끗하며 그만한 가치가 있도록 충분히 성능을 발휘합니다. 당신의 대안은 계획하고 실행하기가 상당히 어려울 거대한 쿼리를 작성하는 것입니다. 일반적으로 PostgreSQL에서 작업을 수행하는 것이 좋습니다. 일반적으로 적절하게 수행하기 위해 설명하는 방식으로 수만 행에 대한 업데이트를 찾았지만 피해야 할 중요한 사항이 있습니다.

이를 수행하는 방법은 삭제시 선택 및 조인을 사용하는 것입니다.

DELETE FROM foo WHERE id IN (select id from rows_to_delete);

어떤 상황에서도 다음과 같이 큰 테이블을 사용해서는 안됩니다.

DELETE FROM foo WHERE id NOT IN (select id from rows_to_keep);

이로 인해 중첩 루프 반 결합이 발생하여 성능이 다소 저하 될 수 있습니다. 해당 경로로 이동해야하는 경우 대신 다음을 수행하십시오.

DELETE FROM foo 
WHERE id IN (select id from foo f 
          LEFT JOIN rows_to_keep d on f.id = d.id
              WHERE d.id IS NULL);

PostgreSQL은 일반적으로 잘못된 계획을 피하는 데 능숙하지만 여전히 좋은 계획과 나쁜 계획 사이에 큰 차이를 만들 수있는 외부 조인과 관련된 경우가 있습니다.

이것은 조금 더 멀리 방황하고 있지만 IN에서 NOT IN으로 이동하여 쿼리 성능 탱크를 보는 것이 얼마나 쉬운 지 언급 할 가치가 있다고 생각합니다.


감사합니다! 그러나이 경우 "조합 쿼리"를 사용하는 것이 더 효율적이라는 것을 알았습니다. 예 IN ( select id from foo except select id from rows_to_keep ) 를 참조 postgresql.org/docs/9.4/static/queries-union.html
UFO에

1

비슷한 문제가 있었기 때문에이 질문을 보았습니다. 300M + 행이있는 데이터베이스를 정리하고 있는데 최종 데이터베이스는 원래 데이터의 약 30 % 만 보유합니다. 비슷한 시나리오에 직면 한 경우 실제로 새 테이블에 삽입하고 삭제하는 대신 색인을 다시 만드는 것이 더 쉽습니다.

같은 일을

CREATE temp_foo as SELECT * FROM foo WHERE 1=2;
INSERT INTO temp_foo (SELECT * FROM foo where foo.id IN (SELECT bar.id FROM BAR);

foo 및 bar에 대한 적절한 색인화를 통해 Seq 스캔을 피할 수 있습니다.

그런 다음 테이블을 다시 인덱싱하고 이름을 바꿔야합니다.

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