Hint Bits/ja

From PostgreSQL wiki
Jump to navigationJump to search

PostgreSQLのMVCC機構は多くの有用な機能を提供しますが、いくつかのこの実装の副作用があります。 その1つは、読み取っただけであるにも関わらずデータベーステーブルに大量に書き込まれることになる、ヒントビット処理の巡回です。

ヒントビットは、コミットまたはアボートされたことがわかったトランザクションにより作成、削除またはその両方の処理をされたタプルに印付けするために使用されます。 これらのビット集合なしでタプルの可視性を決定するためには、pg_clogとおそらくpg_subtransを参照しなければならなくなります。 これは高価な検査です。 一方で、タプルがビット集合を持てば、その状態が分かります。 (または、最悪の場合でも、pg_clogを検索することなく、現在のスナップショットから簡単に計算できます。)

以下の4つのヒントビットがあります。

  • XMIN_COMMITTED -- コミットされたことが既知の作成トランザクション
  • XMIN_ABORTED -- アボートされたことが既知の作成トランザクション
  • XMAX_COMMITTED -- 同上。ただし削除トランザクション用
  • XMAX_ABORTED -- 同上

XMINビットのいずれも設定されいない場合は以下のいずれかです。

  • 作成トランザクションが実行中である場合。これは共有メモリ内で実行中のトランザクションを確認することで検査できます。
  • 終了した後に最初に検査した場合。この場合pg_clogを参照し、トランザクションの状態を確認しなければなりません。また、最終状態がわかったらヒントビットを更新することができます。

タプルが削除と印付けされていた場合、同様の記録がXMAXビットに付けられます。

バキュームまたは任意の通常のDML操作のいずれかによるタプルの確認はすべて、その確認時にこのヒントビットを挿入/削除トランザクションのコミット/アボート状態に一致するように更新します。 テーブル全体に対する通常のSELECT、count(*)、VACUUMは可視性に関してすべてのタプルを検査し、ヒントビットを設定します。

他にもヒントビットがタプル単位で検査、設定されるということにも注意してください。 単純な走査ではページ上の全タプルにアクセスし、そのヒントビットを一度に更新しますが、ばらばらのアクセス(インデックススキャンを介した単一タプルの取り出しなど)では、各種ヒントビットを更新するために同一ページに多く書き込みする可能性があり、時間がかかります。

コミットログ

ここに記載したものの一部はsrc/backend/access/transam/READMEにあります。

  • "pg_clogはXIDを代入された各トランザクションのコミット状態を記録します。"
  • トランザクションと副トランザクションでは、最初にこれを必要とする何か(通常はタプルの挿入・更新・削除ですが、他にもいくつかXIDの代入が必要になる箇所があります)を行った際に永続XIDが代入されます。

pg_clogは副トランザクション、主トランザクションの終了時にのみ更新されます。 トランザクションIDが代入される時、すでに存在するか、存在しなければ初期化されているかどうかを確認するためにトランザクションIDが含まれるclogページが検査されます。

pg_clogには8kB単位のページが割り当てられます。 各トランザクションは2ビット必要ですので、1つの8kBページには4トランザクション/バイト * 8k バイト = 32k トランザクション分の領域があります。

割り当て時、ページはゼロで初期化されます。 このビットパターンは「トランザクションは進行中」を表します。 このためトランザクションが起動する時、その状態を含むpg_clogページが割り当てられているかどうかのみを確認する必要がありますが、何も書き込む必要はありません。 8.3以降では、トランザクションの起動時にこれは起こりません。Xidの割り当て時(つまりトランザクションが最初に読み取り・書き込みコマンドを呼び出した時)に起こります。 過去のバージョンでは、最初にスナップショットが取られた時、非常に少ない例外がありますが通常は、種類を問わない最初のコマンドを実行した時に起こります。

これは、32Kのトランザクションを書き込む度にトランザクションは、そのXIDを割り当てる時に余計な作業、つまりpg_clogの次のページを作成しゼロで初期化する作業をしなければならないことを意味します。 これは問題のトランザクションを遅くするだけではありません。 次にXIDが必要となった時にゼロで初期化中であれば、待機しなければなりません。 これがおそらく報告された、トランザクションの実行時間が予想しないほど長くなる動作の説明です。

CLOGページは内部CLOGバッファがいっぱいになるまでディスクへ書き出しません。 ここにはもっとも使用時期が古いバッファが永続ストレージに吐き出されます。 CLOG pages don't make their way out to disk until the internal CLOG buffers are filled, at which point the least recently used buffer there is evicted to permanent storage.

元原稿: