私はPostgreSQLにデータベースを積極的に自動バキュームさせようとしています。私は現在、次のように自動掃除機を設定しています:
自動バキュームが作動するのは、データベースに負荷がかかっていないときだけなので、ライブタプルよりも死んだタプルの方がはるかに多い場合があります。例については、添付のスクリーンショットを参照してください。テーブルの1つには23のライブタプルがありますが、真空を待っている16845のデッドタプルがあります。それは正気ではありません!
テストの実行が終了し、データベースサーバーがアイドル状態になると、自動バキュームが作動します。これは、データベースがすでに使用されているため、デッドタプルの数が20%ライブタプル+ 50を超えたときに自動バキュームを作動させたいので、これは望ましくありません。構成されています。サーバーがアイドル状態のときの自動バキュームは、私にとって役に立たないものです。本番サーバーは、持続期間中に毎秒数千回の更新に達すると予想されるため、サーバーに負荷がかかっているときでも自動バキュームを実行する必要があります。
私が見逃しているものはありますか?サーバーの負荷が高いときに自動バキュームを強制的に実行するにはどうすればよいですか?
更新
これはロックの問題でしょうか?問題のテーブルは、挿入後トリガーを介して入力されるサマリーテーブルです。これらのテーブルは、同じ行への同時書き込みを防ぐために、SHARE ROW EXCLUSIVEモードでロックされます。
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の動作を調整する必要があるためのより良い答えです。 。
繰り返しますが、実際の問題に対処することはほとんどありません。
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;
はい、それはロックの問題です。これによると ページ (非フル)VACUUMはSHARE UPDATE EXCLUSIVEアクセスを必要とし、これは使用しているロックレベルによってブロックされます。
このロックが必要ですか? PostgreSQLはACIDに準拠しているため、シリアル化違反が発生するとPostgreSQLがトランザクションの1つを中止するため、ほとんどの場合、同時書き込みは問題になりません。
また、 SELECT FOR UPDATE を使用して行をロックし、テーブル全体ではなく行をロックすることもできます。
ロックを使用しない別の方法は、トランザクション 分離レベル シリアライズ可能を使用することです。ただし、これは他のトランザクションのパフォーマンスに影響を与える可能性があるため、より多くのシリアル化の失敗に備える必要があります。
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 |
既存の「自動バキュームの資格」スクリプトは非常に便利ですが、(正しく説明されているように)テーブル固有のオプションがありませんでした。これらのオプションを考慮に入れた修正バージョンを次に示します。
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;