web-dev-qa-db-ja.com

PostgreSQLでの積極的な自動バキューム

私はPostgreSQLにデータベースを積極的に自動バキュームさせようとしています。私は現在、次のように自動掃除機を設定しています:

  • autovacuum_vacuum_cost_delay = 0#コストベースの掃除機をオフにする
  • autovacuum_vacuum_cost_limit = 10000#最大値
  • autovacuum_vacuum_threshold = 50#デフォルト値
  • autovacuum_vacuum_scale_factor = 0.2#デフォルト値

自動バキュームが作動するのは、データベースに負荷がかかっていないときだけなので、ライブタプルよりも死んだタプルの方がはるかに多い場合があります。例については、添付のスクリーンショットを参照してください。テーブルの1つには23のライブタプルがありますが、真空を待っている16845のデッドタプルがあります。それは正気ではありません!

Lots of Dead Tuples

テストの実行が終了し、データベースサーバーがアイドル状態になると、自動バキュームが作動します。これは、データベースがすでに使用されているため、デッドタプルの数が20%ライブタプル+ 50を超えたときに自動バキュームを作動させたいので、これは望ましくありません。構成されています。サーバーがアイドル状態のときの自動バキュームは、私にとって役に立たないものです。本番サーバーは、持続期間中に毎秒数千回の更新に達すると予想されるため、サーバーに負荷がかかっているときでも自動バキュームを実行する必要があります。

私が見逃しているものはありますか?サーバーの負荷が高いときに自動バキュームを強制的に実行するにはどうすればよいですか?

更新

これはロックの問題でしょうか?問題のテーブルは、挿入後トリガーを介して入力されるサマリーテーブルです。これらのテーブルは、同じ行への同時書き込みを防ぐために、SHARE ROW EXCLUSIVEモードでロックされます。

42
CadentOrange

Eelkeは、あなたのロックが自動バキュームをブロックしていることはほぼ間違いなく正しいです。 Autovacuumは、意図的にユーザーアクティビティに道を譲るように設計されています。これらのテーブルがロックされている場合、autovacuumはそれらをバキュームできません。

しかし、後世のために、私はあなたが与えた設定がそれを完全に行わないので、超攻撃的な自動バキュームの設定の例のセットを挙げたかった。ただし、autovacuumをよりアグレッシブにしても、問題が解決することはほとんどありません。また、デフォルトの自動バキューム設定は、DBT2を使用して200以上のテストを実行し、設定の最適な組み合わせを探すことに基づいているため、特に考えなければならない明確な理由がない限り、またはデータベースが大幅に外部にある場合を除き、デフォルトは適切であると想定する必要があります。 OLTPデータベースの主流(たとえば、1秒あたり10Kの更新を取得する小さなデータベース、または3TBのデータウェアハウス)。

まず、ロギングをオンにして、autovacuumが意図したとおりに動作しているかどうかを確認できるようにします。

log_autovacuum_min_duration = 0

次に、autovacワーカーを増やし、テーブルをより頻繁にチェックするようにします。

autovacuum_max_workers = 6
autovacuum_naptime = 15s

自動バキュームと自動分析のしきい値を下げて、より早くトリガーできるようにします。

autovacuum_vacuum_threshold = 25
autovacuum_vacuum_scale_factor = 0.1

autovacuum_analyze_threshold = 10
autovacuum_analyze_scale_factor = 0.05 

次に、autovacuumの割り込みを少なくして、完了までの時間を短縮しますが、同時ユーザーアクティビティへの影響が大きくなります。

autovacuum_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000

一般的にアグレッシブな自動バキュームのための完全なプログラムがあります。これは、小さなデータベースが非常に高い更新率を取得するのに適している可能性がありますが、同時ユーザーアクティビティに大きな影響を与える可能性があります。

また、 autovacuumパラメータはテーブルごとに調整できます に注意してください。これは、ほとんどの場合、autovacuumの動作を調整する必要があるためのより良い答えです。 。

繰り返しますが、実際の問題に対処することはほとんどありません。

40
Josh Berkus

Autovacuumに適格なテーブルを確認するためだけに、次のクエリを使用できます( http://www.postgresql.org/docs/current/static/routine-vacuuming.html に基づく)。ただし、クエリはテーブル固有の設定を検索しないことに注意してください。

 SELECT psut.relname,
     to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
     to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
     to_char(pg_class.reltuples, '9G999G999G999') AS n_tup,
     to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup,
     to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
         + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
            * pg_class.reltuples), '9G999G999G999') AS av_threshold,
     CASE
         WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
             + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
                * pg_class.reltuples) < psut.n_dead_tup
         THEN '*'
         ELSE ''
     END AS expect_av
 FROM pg_stat_user_tables psut
     JOIN pg_class on psut.relid = pg_class.oid
 ORDER BY 1;
36
pygrac

はい、それはロックの問題です。これによると ページ (非フル)VACUUMはSHARE UPDATE EXCLUSIVEアクセスを必要とし、これは使用しているロックレベルによってブロックされます。

このロックが必要ですか? PostgreSQLはACIDに準拠しているため、シリアル化違反が発生するとPostgreSQLがトランザクションの1つを中止するため、ほとんどの場合、同時書き込みは問題になりません。

また、 SELECT FOR UPDATE を使用して行をロックし、テーブル全体ではなく行をロックすることもできます。

ロックを使用しない別の方法は、トランザクション 分離レベル シリアライズ可能を使用することです。ただし、これは他のトランザクションのパフォーマンスに影響を与える可能性があるため、より多くのシリアル化の失敗に備える必要があります。

11
Eelke

Autovacuumプロセスの数を増やし、naptimeを減らすことはおそらく役立つでしょう。バックアップ情報を保存するサーバーで使用するPostgreSQL 9.1の構成は次のとおりです。その結果、挿入アクティビティが大量に発生します。

http://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html

autovacuum_max_workers = 6              # max number of autovacuum subprocesses
autovacuum_naptime = 10         # time between autovacuum runs
autovacuum_vacuum_cost_delay = 20ms     # default vacuum cost delay for

また、cost_delayを下げて、掃除機をより攻撃的にします。

Pgbenchを使用してautovacuumingをテストすることもできます。

http://wiki.postgresql.org/wiki/Pgbenchtesting

高競合の例:

Bench_replicationデータベースを作成する

pgbench -i -p 5433 bench_replication

Pgbenchを実行する

pgbench -U postgres -p 5432 -c 64 -j 4 -T 600 bench_replication

自動バキューム状態を確認する

psql
>\connect bench_replicaiton
bench_replication=# select schemaname, relname, last_autovacuum from pg_stat_user_tables;
 schemaname |     relname      |        last_autovacuum        
------------+------------------+-------------------------------
 public     | pgbench_branches | 2012-07-18 18:15:34.494932+02
 public     | pgbench_history  | 
 public     | pgbench_tellers  | 2012-07-18 18:14:06.526437+02
 public     | pgbench_accounts | 
6
Craig Efrein

既存の「自動バキュームの資格」スクリプトは非常に便利ですが、(正しく説明されているように)テーブル固有のオプションがありませんでした。これらのオプションを考慮に入れた修正バージョンを次に示します。

WITH rel_set AS
(
    SELECT
        oid,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)::BIGINT
        END AS rel_av_vac_threshold,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)::NUMERIC
        END AS rel_av_vac_scale_factor
    FROM pg_class
) 
SELECT
    PSUT.relname,
    to_char(PSUT.last_vacuum, 'YYYY-MM-DD HH24:MI')     AS last_vacuum,
    to_char(PSUT.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
    to_char(C.reltuples, '9G999G999G999')               AS n_tup,
    to_char(PSUT.n_dead_tup, '9G999G999G999')           AS dead_tup,
    to_char(coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples, '9G999G999G999') AS av_threshold,
    CASE
        WHEN (coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples) < PSUT.n_dead_tup
        THEN '*'
    ELSE ''
    END AS expect_av
FROM
    pg_stat_user_tables PSUT
    JOIN pg_class C
        ON PSUT.relid = C.oid
    JOIN rel_set RS
        ON PSUT.relid = RS.oid
ORDER BY C.reltuples DESC;
6
Vadim Zingertal