거대한 테이블에 직렬 열을 추가하는 가장 효율적인 방법


10

거대한 테이블에 BIGSERIAL 컬럼을 추가하는 가장 빠른 방법 은 무엇입니까 (~ 3GB, ~ 174Gb)?

편집하다:

  • 기존 행의 열 값을 늘리고 싶습니다 ( NOT NULL).
  • 필 팩터를 설정하지 않았습니다 (돌이켜 보면 나쁜 결정처럼 보입니다).
  • 디스크 공간에 문제가 없으며 가능한 한 빨리 디스크 공간을 원합니다.

답변:


12

무엇이 잘못 되었나요?

ALTER TABLE foo ADD column bar bigserial;

고유 한 값이 자동으로 채워집니다 (1로 시작).

기존의 모든 행에 대해 숫자를 원하면 테이블의 모든 행을 업데이트해야 합니다. 아니면 그렇지 않습니까?

데이터 페이지에서 죽은 튜플이나 여유 공간을 재사용 할 수없는 경우 테이블 크기가 두 배로 늘어납니다. 작업 성능은 FILLFACTOR100보다 낮거나 테이블에 임의의 데드 튜플이 퍼져 많은 이점을 얻을 수 있습니다 . 그렇지 않으면 VACUUM FULL ANALYZE나중에 디스크 공간을 복구하기 위해 실행해야 할 수도 있습니다 . 그러나 이것은 빠르지 않습니다.

pgstattuple
이 확장에 관심이있을 수 있습니다. 테이블에서 통계를 수집하는 데 도움이됩니다. 죽은 튜플 및 여유 공간에 대해 확인하려면 다음을 수행하십시오.

databae 당 한 번 확장 설치 :

CREATE EXTENSION pgstattuple;

요구:

SELECT * FROM pgstattuple('tbl');

대안

뷰, 외래 키 등에 따라 새 테이블을 만들 여유가 있다면 ...

이전 테이블의 빈 복사본을 만듭니다.

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

bigserial 열을 추가하십시오.

ALTER new_tbl ADD column bar bigserial;

이전 테이블의 데이터를 삽입하고 bigserial을 자동으로 채 웁니다.

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster

새 bigserial 열이 INSERT의 SELECT에 누락되어 기본값으로 자동 채워집니다 . 모든 열을 철자 nextval()하고 SELECT목록에 동일한 효과를 추가 할 수 있습니다 .

새 테이블에 모든 데이터가 있는지 확인하십시오.
인덱스, 제약, 당신은 이전 테이블에 있었다 트리거 추가 해주기를 .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

전반적으로 상당히 빠를 수 있습니다. 이렇게하면 팽창없이 바닐라 테이블 (및 인덱스)이 남습니다.

테이블 상태에 따라 기존 테이블의 크기 주위에 사용 가능한 디스크 공간이 흔들림 공간으로 필요합니다. 그러나 테이블 팽창으로 인해 첫 번째 간단한 방법으로 많은 것이 필요할 수 있습니다. 다시, 세부 사항은 테이블 상태에 따라 다릅니다.


3
대안을 단일 트랜잭션으로 감싸면 훨씬 빠릅니다. 추가 fsyncs 를 피할 것입니다
Frank Heikens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.