数十のデータベースを持つクラスターがあります。先月9.6にアップグレードしたときは、9.3で1年間(時間の経過とともに成長して)順調に稼働していました。それ以降、データベースは、大きなテーブル(10万行以上のテーブル)の更新時に1分から30〜60分の間でフリーズします。
具体的には、プロセスの1つが、このようなテーブルの複数の列を一度に1つずつ更新し、コードログで、最大30分間、一時停止およびハングした場所を確認し、その後、何もないかのように取得します。発生し、数秒以内に、そのようなハングなしで同じ内の多くの連続した列を更新します。
データベースへのロギングを増やしても、最初は何も表示されませんでした。サーバーとpostgresでのメモリ使用量の分析では、リソース使用量に異常は見られませんでした。最終的に、デバッグレベルのロギングを使用して、postgresqlがすべてのデータベースをバキュームし、自動バキューマーがそのデータベースにヒットした後、問題のクエリが解除されることを確認できましたが、すべてのデータベースの最初のループではありません。しかし、数回のパスの後。それ以来、私は自動真空設定をいじっています。 9.3でオフになっていて、どういうわけか生き残ったので、自動バキュームをオフにしてみましたが、それは役に立ちませんでした。そこで電源を入れて、いろいろな設定を変えていきました。頻繁な自動バキュームや16人のワーカーの追加などによって、本番サーバーがこのようにハングしないようにしました。
私はデータベースサーバーに対して一般的に持っている設定を貼り付けています-一般的なメモリ設定はpgtuneで作成されました。これは、私が本質的にいじくり回してきた自動真空設定です。
私は学んでいますが、暗闇の中で非常に撮影しています-誰かが分析を処理するための最良の方法(ログなどを介して)と9.6のこのインスタンスでの自動バキュームの最適化についてのガイダンスを提供できるなら、それが私が求めているものです。
公式サイトおよびここでロックを表示するように設計されたさまざまなクエリでは、待機中のプロセスはまったく表示されませんが、pg adminivダッシュボードに「AccessShareLock」と「RowExclusiveLock」を持つプロセスの各エントリが少なくとも1つ表示されます、[ロック]の下で、列を更新するクエリが実行されているとき。
繰り返しになりますが、イライラするのは、一度に数十万レコードの列更新についてそれほど複雑なことはわかりませんが、ハングの原因を簡単に確認できるはずです(自動バキュームに関するもの)。 、およびそれを修正する方法。以下の設定は本番環境で機能しているように見えますが、その理由がわかりません。それらを改善する方法も、開発サーバーでワーキングセットの構成を作成する方法もわかりません。あなたの助けに感謝します。
autovacuum = on
log_autovacuum_min_duration = 200
autovacuum_max_workers = 16
autovacuum_naptime = 1min
autovacuum_vacuum_threshold = 5000
#autovacuum_analyze_threshold = 500
#autovacuum_vacuum_scale_factor = 0.2
#autovacuum_analyze_scale_factor = 0.1
#autovacuum_freeze_max_age = 200000000
#autovacuum_multixact_freeze_max_age =
autovacuum_vacuum_cost_delay = 20ms
autovacuum_vacuum_cost_limit = 2000
default_statistics_target = 100
maintenance_work_mem = 2920MB
checkpoint_completion_target = 0.8
effective_cache_size = 22GB
work_mem = 260MB
wal_buffers = 16MB
shared_buffers = 7680MB
min_wal_size = 80MB
max_wal_size = 2GB
戦略を変えることをお勧めします。
具体的には、プロセスの1つがそのようなテーブルのいくつかの列を更新します一度に1つずつそしてコードログで、最大30分間、一時停止してハングする場所を確認できます。その後、何も起こらなかったかのように後で取得し、数秒以内に、そのようなハングなしで同じ内の多くの連続する列を更新します。
各UPDATE
は基本的に1つのDELETE
1と同等であるため、そのような更新の1つはテーブルのサイズを簡単にdoubleできますINSERT
、これにより、各deleted行は、テーブルがVACUUM
され、そのスペースを再利用できるようになるまで、無駄なスペースを占有します。 UPDATE
sの次のラウンドのために。
できるよ:
戦略を変更し、一度にできるだけ多くの列を更新します。データへのアクセス回数が大幅に減るため、プロセスははるかに高速になります。
各VACUUM
ラウンドの後にコードからUPDATE
を発行して、未使用のスペースが次のUPDATE
ラウンドで使用できるようにします。
状況によっては、(たとえば)1.000のバッチでUPDATE
sを実行し、各バッチの後にコミットすると、状況が緩和される場合があります。
3つの手法を任意に組み合わせると、おそらく更新が容易になります。