vacuum (3)

vacuum_delay_point

vacuumを実行するプロセスよりも通常のトランザクションを実行するプロセスを優先させるために、sleepを実行してvacuumプロセスを遅延させる。この仕組みはpostgresql.confでvacuum_cost_delayを1以上に設定したときに有効になる。この関数はvacuum中に1ページ処理するごとなど、頻繁に実行され、sleepするかどうか判定している。

sleepする条件は以下のとおり。
(1)VacuumCostActiveがtrue
VacuumCostActiveはvacuumの開始時に設定される。VacuumCostDelay(postgresql.confのvacuum_cost_delay)が1以上のときtrueになる。

        VacuumCostActive = (VacuumCostDelay > 0);

(2)InterruptPendingがfalse
InterruptPendingは、プロセスの中断要求があったときにtrueになる。中断要求があった場合は中断させるのが優先なので、sleepしない。

(3)VacuumCostBalanceがVacuumCostLimitに達した時
VacuumCostBalanceはvacuumの開始時に0に設定され、以下の処理が実行されたときに加算される。

  • ReadBufferでキャッシュヒットしたとき、vacuum_cost_page_hitが加算される
  • ReadBufferでキャッシュミスしたとき、vacuum_cost_page_missが加算される
  • WriteBufferでページをdirtyにしたとき、vacuum_cost_page_dirtyが加算される

(これらのパラメータについては、PostgreSQLのマニュアルに詳しい記述がある)

sleepする時間は以下の式で計算される。最大値はVacuumCostDelay * 4に制限している。

        msec = VacuumCostDelay * VacuumCostBalance / VacuumCostLimit;
        if (msec > VacuumCostDelay * 4)
            msec = VacuumCostDelay * 4;

この仕組みを有効にした場合、vacuumプロセスの優先度を下げることにより、他のトランザクションを実行するプロセスの性能が悪くならない効果があると考えられる。しかし、full vacuumのときでもvacuumが遅延するため注意が必要。full vacuumはテーブルをAccessExclusiveLockするのでテーブルの検索もブロックされてしまう。full vacuum中のテーブルを使用するトランザクションはvacuumが終るまで待たされることになるので、vacuum_cost_delayを大きくしすぎると逆効果になるかもしれない。