Better VACCUM FULL For PostgreSQL 9.0
원문:https://wiki.postgresql.org/wiki/What’s_new_in_PostgreSQL_9.0#Better_VACUUM_FULL
지금까지 VACUUM FULL 은 매우 느렸다. 이 구문(Statement)는 테이블로부터 빈공간을 확보하고 그것의 크기(Size)를 줄였지만 VACUUM 은 만족할만큼 빠르게 동작하지 않았다.
이것이 느린 이유는 동작 방법에 문제가 있었기 때문이다. 레코드를 그들의 소스블럭으로부터 테이블에 시작점에 가까운 블럭으로 하나하나씩 읽어서 옮겼었다. 그리고 테이블에 끝이 빈공간이면 그 부분을 지웠다.
전략적으로 이러한 방법은 매우 비효율적(Inefficient) 이다. 레코드를 하나하나씩 옮기는 것은 랜덤 I/O를 발생시킨다. 게다가, 인덱스(Index)를 재구성하는 동안에 그것을 유지하고, 더 많은 비용이 들어가는, 인덱스는 파편화된다. 이럴바에는 VACUUM FULL이 다 끝나고 나서 재인덱스(reindex)를 하는 것이 낫다.
Version 9.0 에서 VACUUM FULL은 테이블과 동일한 또 하나의 테이블을 만들고 거거에 모든 레코드를 순차적이게 복사한다. 모든 레코드가 복사되고 나면, 인덱스를 재생성하고 예전 테이블은 삭제되고 새로운 테이블로 대체된다.
이것은 VACUUM 을 보다 빠르게 한다. 하지만 VACUUM FULL은 동작하는 동안에 AccessExclusiveLock 을 필요로 한다. 이전 방법과 비교했을때 이 방법의 결점은 VACUUM FULL을 했을 경우 새로운 버전의 테이블을 만들기 위해서 디스크에 테이블 크기의 2배의 용량을 사용할 수 있다는 것이다.
이제, 두가지 방법에 대해서 실시간으로 비교를 해보자. 먼저 아래와 같은 방법으로 테스트 데이터를 준비 했다.
1 2 3 4 5 6 7 8 9 10 |
marc=# CREATE TABLE test (a int); CREATE TABLE marc=# CREATE INDEX idxtsta on test (a); CREATE INDEX marc=# INSERT INTO test SELECT generate_series(1,1000000); INSERT 0 1000000 marc=# DELETE FROM test where a%3=0; -- making holes everywhere DELETE 333333 marc=# VACUUM test; VACUUM |
8.4 버전에서는.
1 2 3 4 5 6 7 8 |
marc=# \timing Timing is on. marc=# VACUUM FULL test; VACUUM Time: 6306,603 ms marc=# REINDEX TABLE test; REINDEX Time: 1799,998 ms |
다 합해 대충 9초 정도 걸렸다.
9.0 버전에서는.
1 2 3 4 5 |
marc=# \timing Timing is on. marc=# VACUUM FULL test; VACUUM Time: 2563,467 ms |
아직 이것은 제품에서(아마 서비스중에라는 뜻인듯..) VACUUM FULL 이 좋은 아이디어라는 뜻은 아니다. 만약 이것이 필요하다면, 아마도 VACUUM 정책이 올바르지 않기 때문일 것이다. (응?)