Postgresは、MVCC(多版式同時実行制御)の追記型なので、新規行作成(INSERT)だけでなく、
更新(UPDATE)の場合も内部では行データ(タプルという)が新たに増えていきます。
そのため、UPDATEを繰り返すだけでも、データがどんどん増えていき、
パフォーマンスが極端に落ちてしまうことがあります。
これを解決するために、Postgresでは、不要な行データを削除すること(バキュームという)が
必要となってきます。
昔は、バキュームコマンドを定期的に実行する必要がありましたが、
最近のPostgresでは、オートバキューム機能があるため、特に気にすることもなく、
勝手にバキュームしてくれます。
と、思っていましたが・・・
どういうわけか、担当プロジェクトの大量データ処理で激しい処理落ちが・・・
そして、原因調査へ
■まずは、バキューム関係のパラメータを設定
バキュームログを出力して、状況の詳細を確認する。
Postgres.confで、バキュームログを出力するように設定
autovacuum = on
log_autovacuum_min_duration = 0
※postgresの再起動が必要
※postgres.confは、デフォルトなら「C:\Program Files\PostgreSQL\9.x\data」にあるはず。
■ログの確認
そして、再実行して、処理落ちがはじまったところでログを見てみると
やはり、タプルが残っていて、バキュームされていないように見える。
※このテーブル「ad_sequence」の実際の行は1479行であり、それに対してタプルが多すぎる。
※Postgresのログは、デフォルトなら「C:\Program Files\PostgreSQL\9.x\data\pg_log」に
日時付ファイル名で出力されている。
■さらに、PGAdminで、タプル状態の確認
これを見ても、やはり、タプルが残っているようだ。
■いろいろググッてみると、
Let's Postgresの以下のサイトを見つけた。
HOT(Heap Only Tuples) ~ Let's Postgres
HOT(Heap Only Tuple)といわれる機能があって、バキューム処理をしてくれるらしいのだが・・・
だけど、処理が激落ちしているので、それすら走っていない気がする。
そして、さらに上記サイトを読み進めていくと
ロングトランザクションに気をつけようということにひっかかる。
■ロングトランザクションとコネクションプールに注意!!!
改めて、ソースを確認していくとなんとコミット漏れがあり
それをコミットすることで状況は無事解決した。
(めでたし、めでたし、苦労のわりには、原因はイージーミスという情けない幕切れ。)
実行中のトランザクションで、更新されたテーブルは
そのトランザクションが終了するまでバキュームされないようだ。
ここでもうひとつ注意が必要なのは、コネクションプールについてである。
コネクションプールを使っていると、トランザクションがコミットされていても
バキュームされないことがあるようだ。
詳細不明だが、コネクションプールの機能は、プログラムからコネクションをクローズしても
物理的なコネクションはクローズされず、ある程度の期間(KeepAlive)、
コネクションを保持したり、使いまわしをするもののため、
そのKeepAliveの間は解放されないのではないかと推測しています。
なので、大量データ処理では、コネクションプールを使わず、コネクションの時間的コストはかかるが、適度なタイミングで、コネクションを解放して、再接続をしたほうがいいという結論に至りました。
0 件のコメント:
コメントを投稿