Open5
postgresの勉強
フロントエンドとバックエンド
(通信プロトコルの話)
- TCP/IP(またはUnixドメインソケット)で通信
- フロントエンド/バックエンドプロトコル、またはプログラム名を取ってlibpqプロトコル
- Ver3を今では使う。Ver2も互換性はある、postgres側で。
- ワイヤプロトコルみたいな言い方もないか?
- 開始パケットは特殊、開始はどこからどこまでの範囲を指す?
- 簡易と拡張の2つのサブプロトコルがある。
- 拡張問い合わせプロトコルは、パースーバインドー実行でSQLを実行する。JavaのJDBCなど。
(バックエンドプロセスの構造)
- postmasterからバックエンドプロセスが起動される。
- 処理フローは今日の後半で。
- バックエンドで利用されるデータ構造、pg_commit_ts(トランザクションのコミット時刻のデータを保有)
- サブディレクトリはdatabaseごと、1がglobal?
- ファイル名はfilne node番号に基づいている。
- ヒープ、インデックスファイルの最大は1GB。
- 多くの場合、file node番号とOIDと一致するが、TRUNCATE等で変わることはある。
- Index Access Method、Table Access Methodの標準的な例のみ考慮。
(モジュール構造)
- postmasterやtcopなどのモジュール構造。
- accessにTAM(今はHeapのみ)、Index Access Methodなどのコードがある。同じフォルダのtransamなどがトランザクションマネージャ。
- util/mmgrがPostgreSQLのメモリマネージャ。(プロセス内)とはどういうこと? 共有バッファではないとのこと。
- palloc(mallocより便利らしい)もここに含まれる。
(ソース調査やデバッグの手法)
- VimやEmacs向けにタグを付けることができる。
- gdbでデバッグすることができる。
データ構造
- Slotted Pageの話。
- 昔は1ブロックに複数ページというあんもあったようだが、今ではブロック=ページ
- タプルヘッダにはxmin/xmaxなどトランザクションに重要なデータが含まれる。
- HOTで更新時の負荷を減らす。
- TOASTで8KBのページからオーバーフローしたデータを格納可能にする。
- FSM(Free Space Map)って何だっけ。ヒープの空き領域を管理する特殊なファイル。
- 二分木で管理されていて、リーフノードには空き領域の大きさを表す1バイトの値が入っている。
- FSMの更新するのは面倒じゃないのかな?
- Visibility Map(可視性マップ)
- ラージオブジェクトとTOASTは別か。ラージオブジェクトでは部分的な読み取り、更新が効率的に出来る?
- Btreeというより、B+ Treeの説明。
- 共有バッファ内のバッファタグというのは初めて聞いた。
- バッファは最初はフリーリストにある。
- 共有バッファの管理はClock-sweepアルゴリズム
- バルクのRead/Writeでは共有バッファを大幅に置き換えない仕組みが必要。
(ロックの話)
- スピンロック、軽量ロック、レギュラーロックがある。
- SIRead述語ロックはSSIで使われる。
- 軽量ロックは共有バッファ上のデータ構造を保護するのに使われる。排他と共有のモードがある。
- レギュラーロックはテーブル等に関するもの、pg_locksで見えるもの。ラッチを使っている。
- スピンロックはmutex、軽量ロックはセマフォ、レギュラーロックはラッチ?と言ってたかな。
- ロック自体は誰が保持してるロックなのかの情報は持ってない。それをプロセスと紐づけるのがPROCLOCK。
(トランザクション)
- WALを使い、パフォーマンスとリカバリを両立させる。
- pg_multixact?共有行ロックを管理する。
- お、ヒントビットきた。clogなどを見に行かなくても良いよということか。
- full_page_writesはWALに更新後ブロックを書く。
- リソースマネージャって何よ。https://github.com/postgres/postgres/blob/master/src/include/access/rmgrlist.h
- 各更新処理の、機能単位ごとに別々のリソースマネージャが登録されているらしい。
- MVCCのタプルの可視性は、分離レベルごとに異なるタイミングでスナップショットが作られる(更新される)ことで行われている。
- CLOGはトランザクションのコミット状態を2ビットで、pg_xactに保存。
- 実行中/コミット済み/アボート済み/サブコミット済みの4状態。サブコミットって何よ?
- サブコミットはSAVEPOINTなどで使うもので、内部的には親のトランザクションをコミットする際に一度にコミットされる必要があるため、2PCのような形で実装されている。
- この情報をヒントビットに設定し、もしヒントビットが立っていない場合はCLOGを見るようにする。
- 行ロックはタプルヘッダのxmaxを使う?
PostgreSQLの起動と停止
- startupプロセスを起動し、リカバリ(WALの適用)がされる。
- サーバの終了はSmart/Fast/Immediateがある。Smart/Fastではチェックポイントを実行。
クエリ処理の流れ
- パース処理ではSQLを読み込んでパースツリー(raw parse tree)に変換する。
- 字句解析(トークンの切り出し)と構文解析(文法チェック)を行っている。
- SELECTステートメントの構造体にクエリツリーとして生成される。
- アナライズ処理でシステムカタログを参照しながら、クエリツリーに変換する。
- リライト処理でクエリツリーの書き換えを行う。
- プランナはパースツリーから最適な実行計画を作成する。PostgreSQLではコストベースで作成する。
- プランツリーを生成する。
- プランナの処理が非常に多岐に渡る。
- エグゼキュータはノードごとに処理を行い、上位ノードに結果を渡していく。最上位のノードの出力結果が実行結果となる。
- ポータル?問い合わせの実行を管理するデータ構造。カーソルを作ると一つ作られている。
- プランノードはシーケンシャルスキャンのような一つ一つの処理を指す。
- lossyなインデックスを使う場合は、再チェックでフィルタされることがある。"rows removed by index recheck"の表記になる際。
- ハッシュ結合でハイブリッドハッシュ結合なんてものがあるのか。 https://taityo-diary.hatenablog.jp/entry/2017/05/29/055949
- パラレルクエリではプロセス間の通信に動的共有メモリ(DSM)が使われる。
その他レプリケーションやVacuum、Analyzeなど
- Streaming ReplicationではCopy Both(双方向でのやり取りが可能)というここでのみ使われるCOPY文が使われる。
- リカバリの衝突がおこりうる。
- レプリケーションスロットは従来方法のWALがプライマリで削除されるなどの欠点がない。
- logical decordingによる論理レプリケーション。