PostgreSQLのデータ構造と内容を知る
- 便利な外部ツールの一部紹介 -
JPUGしくみ + アプリーケーション分科会 勉強会
2014.5.31
笠原辰仁
@kasa_zip
アジェンダ
●
はじめに
●
PostgreSQLを構成するデータ
●
構造、状況を把握するツール群
●
各種ツールの使い方と代表的な利用例
はじめに
●
本日は、PostgreSQLのデータ構造やその内容を
知るために有用なツールとその簡単な使い方を紹
介します
●
最近はプレ勉強会や永安氏の公開している
PostgreSQL internals など、PostgreSQLの内
部を深く知るための手段や機会が増えてきました
– http://www.postgresqlinternals.org/index.php/
●
内部構造を知る上で、理解の手助けになれば・・
●
また、最近はPostgreSQLの利用シーンも増えて
おり、データ破損などの調査も必要になるケース
が増えているので・・・
PostgreSQLを構成するデータ
●
代表的なデータ
名称 説明 格納先
テーブル テーブルデータ。デフォルトでは8kBブ
ロックの固まりで、1GBファイル1単位に
分割されている。
$PGDATA/base
$PGDATA/global
<テーブルスペース
>/<識別子>/
インデックス インデックスデータ。基本的な構成は
テーブルデータと同じ。
$PGDATA/base
$PGDATA/global<
テーブルスペース>/<
識別子>/
FSM(Free Space Map) テーブル内に存在する空き領域の場所と
大まかな空きサイズをマッピングした
ファイル。
テーブルと同じ
VM(Visibility Map) テーブルのブロック単位での可視マップ
ファイル。1ブロック1bit1で管理。不要
レコードがなければ1
テーブルと同じ
一時ファイル ディスクソートやハッシュ処理時に生成
される一時ファイル。処理終了時に削除
される。
$PGDATA/base/pg
sql_tmp
PostgreSQLを構成するデータ
●
代表的なデータ
名称 説明 格納先
トランザクションログ DBに変更を行った処理のログ $PGDATA/pg_xlog/
コミットログ 各トランザクションのコミット状況
を記録しているログ
$PGDATA/pg_clog/
制御ファイル XIDなどインスタンスの重要なメタ
データを記録しているファイル
(pg_control 512byte 固定)
$PGDATA/global/
稼働統計情報ファイル 内部で取得されている稼働統計情報
のファイル。
$PGDATA/pg_stat/
$PGDATA/pg_stat_tmp/
Multixactファイル
(名前適当)
共有ロック状態を記録しているファ
イル。
$PGDATA/pg_multixact/
Serialファイル
(名前適当)
SSIトランザクションのコミット状況
を記録しているファイル。
$PGDATA/pg_serial/
サブトランザクション
ファイル
SAVEPOINTを使用したサブトラン
ザクションの状況を記録している
ファイル。
$PGDATA/subtrans/
スナップショット
ファイル
pg_export_snapshot()でエクスポー
トしたスナップショット情報。
$PGDATA/pg_snapshots/
PostgreSQLを構成するデータ
●
代表的なデータ
名称 説明 格納先
PreparedTransaction
ファイル
2フェーズコミット用のプリペアトラ
ンザクションの状態を記録てしてい
るファイル。
$PGDATA/pg_twophas
e/
Filenodeマップファイル pg_classを経由しないアクセスが実
施されるシステムカタログのOIDと
物理ファイルのマップファイル
(pg_filenode.map 512byte 固定)
$PGDATA/global/
$PGDATA/base/
relationキャッシュファ
イル
各種リレーションのキャッシュファ
イル(backendの初期化高速用)
(pg_internal.init)
$PGDATA/global/
$PGDATA/base/
設定ファイル PostgreSQLの設定ファイル
(postgresql.conf)
$PGDATA
アクセス制御ファイル PostgreSQLのホストベースのアク
セス制御ファイル
(pg_hba.conf)
$PGDATA
起動コマンドファイル PostgreSQLを起動した際のコマン
ドを記録したファイル
(postmaster.opts)
$PGDATA
便利なツール群(主に開発)
●
データ構造や属性の確認に便利
名称 説明 解析対象 PostgreSQL起
動
pg_filedump
(外部ツール)
テーブルやインデックスデータの物理
イメージをダンプして可視化するツー
ル。
pagseinspectがあればほぼ不要・・
テーブル
インデックス
不要
pg_xlogdump
(9.3からcontrib)
トランザクションログの内容を可視化
するツール。
トランザク
ションログ
不要
pageinspect
(8.3からcontrib)
テーブルやインデックス、FSMのメタ
情報(主にヘッダ情報)を可視化する
ツール
テーブル
インデックス
FSM
必要
便利なツール群(主に検証・運用)
●
データの統計的な俯瞰、確認に便利
名称 説明 解析対象 PostgreSQL起
動
pgstattuplet
(contrib)
テーブルやインデックスの不
要領域や断片化状況を数値化
するツール。
テーブル
インデックス
必要
pg_buffercache
(contrib)
テーブルやインデックスが
PostgreSQLの共有バッファ
にどれだけ格納されているか
を数値化するツール。
テーブル
インデックス
必要
pg_fincore
(外部ツール)
テーブルやインデックスがOS
のファイルキャッシュにどれ
だけ格納されているかを数値
化するツール。
テーブル
インデックス
必要
pg_freespacemap
(contirb)
FSMにマッピングされている
空き領域状況を数値化する
ツール。
FSM 必要
テーブル/インデックスの
ページ構造を調べる
* +-----------------------+---------------------------------+
* | PageHeaderData | linp1 linp2 linp3 ... |
* +---------------+------+---------------------------------+
* | ... linpN | |
* +---------------+-----------------------------------------+
* | ^ pd_lower |
* | |
* | v pd_upper |
* +-------------+-------------------------------------------+
* | | tupleN ... |
* +-------------+-----------------------+-------------------+
* | ... tuple3 tuple2 tuple1 | "special space"|
* +--------------------------------------+-------------------+
* ^ pd_special
●
pageinspect
●
contribに付属しているツール
●
contribモジュールのmakeないしはRPMパッ
ケージ等で導入
– pageinspectを実施したいDBでCREATE
EXTENSION
●
テーブル、インデックス名をインップットし、
ページヘッダやタプルヘッダのメタ情報の調査
に有用
●
手軽に使えておすすめ
pageinspectの出力例(テーブル)
(詳細は include/storage/bufpage.h)
postgres=# SELECT * FROM page_header(get_raw_page('test', 0));
-[ RECORD 1 ]--------
lsn | 0/1F88F90
checksum | 0
flags | 0
lower | 44
upper | 8032
special | 8192
pagesize | 8192
version | 4
prune_xid | 1094
Flagsはページ単位の状態を表すヒント。
PD_PAGE_FULL ,
PD_ALL_VISIBLEなど
Versionはページレイアウトの
* Page layout version
number 0 is for pre-7.3
* Releases 7.3 and 7.4 use 1.
* Release 8.0 uses 2
* Release 8.1 uses 3
* Release 8.3 uses 4
pageinspectの出力例(テーブル)
(詳細は include/access/htup_details.h)
postgres=# SELECT * FROM
heap_page_items(get_raw_page('test', 0));
-[ RECORD 1 ]---------
lp | 1
lp_off | 8160
lp_flags | 1
lp_len | 28
t_xmin | 1097
t_xmax | 0
t_field3 | 0
t_ctid | (0,1)
t_infomask2 | 3
t_infomask | 2049
t_hoff | 24
t_bits | 10000000
t_oid |
lp_flags はラインポインタの状態
0:未使用、1:通常、
2:REDIRECT, 3: DEAD
t_infomaskがタプルの状態を
細かく管理している重要な
フラグ部位。左記は10進数
t_bitsはNULL値の管理
pageinspectの出力例(インデックス)
(詳細は include/access/nbtree.h)
postgres=# SELECT * FROM bt_metap('test_pkey');
-[ RECORD 1 ]-----
magic | 340322
version | 2
root | 1
level | 0
fastroot | 1
fastlevel | 0
pageinspectの出力例(インデックス)
(詳細は include/access/nbtree.h)
postgres=# SELECT * FROM bt_page_stats('test_pkey', 1);
-[ RECORD 1 ]-+-----
blkno | 1
type | l
live_items | 3
dead_items | 0
avg_item_size | 16
page_size | 8192
free_size | 8088
btpo_prev | 0
btpo_next | 0
btpo | 0
btpo_flags | 3
btpo_* はspecial領域に
あるBtree専用の情報
pageinspectの出力例(インデックス)
postgres=# SELECT * FROM bt_page_items('test_pkey', 1);
-[ RECORD 1 ]-----------------------
Itemoffset | 1
ctid | (0,1)
itemlen | 16
nulls | f
vars | f
data | 01 00 00 00 00 00 00 00
-[ RECORD 2 ]-----------------------
itemoffset | 2
ctid | (0,2)
itemlen | 16
nulls | f
vars | f
data | 02 00 00 00 00 00 00 00
ctidはテーブルのライン
ポインタ
data は実際のキー値
pageinspectの出力例(インデックス)
postgres=# SELECT * FROM bt_page_items('test2_idx', 1);
-[ RECORD 1 ]-----------------------
Itemoffset | 1
ctid | (0,1)
itemlen | 16
nulls | f
vars | t
data | 01 00 00 00 09 41 41 41
-[ RECORD 2 ]-----------------------
itemoffset | 2
ctid | (0,2)
itemlen | 16
nulls | f
vars | t
data | 02 00 00 00 09 42 42 42
マルチカラムインデックスは
こんな感じに見える
1, 'AAA'
2, 'BBB'
の16進数表記
(文字の前の09はヘッダ含むサイズ)
9 >> 1 = 4 = (1 + 3)
pg_filedump
●
Pgfoundryで公開されている外部ツール
●
contribモジュール同様の手順でmake &&
make installして利用可能
– PostgreSQLのバージョン毎にコードがある
– PostgreSQL 9.3用はHEADを使う
●
テーブル、インデックスのファイルをインッ
プットし、ページヘッダやタプルヘッダのメタ
情報の調査に有用
pg_filedumpの出力例(テーブル)
pg_filedump -i /Users/postgres/base/pgsql934/base/12297/16486
Block 0 ********************************************************
<Header> -----
Block Offset: 0x00000000 Offsets: Lower 40 (0x0028)
Block: Size 8192 Version 4 Upper 8064 (0x1f80)
LSN: logid 0 recoff 0x01f88dc8 Special 8192 (0x2000)
Items: 4 Free Space: 8024
Checksum: 0x0000 Prune XID: 0x00000446 Flags: 0x0000 ()
Length (including item array): 40
<Data> ------
Item 1 -- Length: 32 Offset: 8160 (0x1fe0) Flags: NORMAL
XMIN: 1091 XMAX: 0 CID|XVAC: 0
Block Id: 0 linp Index: 1 Attributes: 2 Size: 24
infomask: 0x0802 (HASVARWIDTH|XMAX_INVALID)
pg_filedumpの出力例(インデックス)
Block 1 ********************************************************
<Header> -----
Block Offset: 0x00002000 Offsets: Lower 40 (0x0028)
Block: Size 8192 Version 4 Upper 8112 (0x1fb0)
LSN: logid 0 recoff 0x01f89058 Special 8176 (0x1ff0)
Items: 4 Free Space: 8072
Checksum: 0x0000 Prune XID: 0x00000000 Flags: 0x0000 ()
Length (including item array): 40
<Data> ------
Item 1 -- Length: 16 Offset: 8160 (0x1fe0) Flags: NORMAL
Block Id: 0 linp Index: 1 Size: 16
Has Nulls: 0 Has Varwidths: 0
<Special Section> -----
BTree Index Section:
Flags: 0x0043 (LEAF|ROOT|HASGARBAGE)
Blocks: Previous (0) Next (0) Level (0) CycleId (0)
pageinspect vs pg_filedump
●
どちらも大体同じ情報が取れるが、pageinspect
に分がある感じ
●
pageinspectの良さ
– SQLで集計や検索が容易
– テーブルやインデックス名で情報をひける
●
pg_filedumpの良さ
– PostgreSQLが停止してても使える
– infomask等を分かりやすく表示する
– インデックスのFlagの状態が分かる
●
ただ、pg_filedumpはメンテが止まる可能性
が・・
– 9.3も正式版?が出ていない・・
pg_xlogdump
●
contribに付属しているツール
●
contribモジュールのmakeないしはRPMパッ
ケージ等で導入
●
コマンドライン
●
WALファイルをインップットし、トランザク
ションレコードの調査が可能
●
おそらくWALの内部情報を分かりやすくダンプ
する唯一のツール
pg_xlogdumpの出力例
pg_xlogdump base/pgsql934/pg_xlog/000000010000000000000001
rmgr: Heap len (rec/tot): 35/ 67, tx: 1000,
lsn: 0/01B25020, prev 0/01B24FE0, bkp: 0000,
desc: insert(init): rel 1663/12297/16384; tid 0/1
rmgr: Transaction len (rec/tot): 12/ 44, tx: 1000,
lsn: 0/01B25068, prev 0/01B25020, bkp: 0000,
desc: commit: 2014-04-26 19:51:36.311101 JST
rmgr(resource manager)は処理カテゴリのようなもの。
len は rec:rmgrに関連するもののみのレコード長
totはトランザクションレコード全体の長さ。
txはトランザクションID
bkp はフルページのバックアップをしたかのフラグ。
descはトランザクションの処理内容
pg_xlogdump 活用方法?
●
運用でお世話になることは少ない・・
●
フルページの割合の調査には有用か
– Bkpフラグ等で確認できる
●
rmgrで絞れば、例えばテーブルの
CREATE/DROPなどを抽出できる
– 大事なデータやテーブルの削除処理が分かるので、
オペミスからの復旧に使える
– 大事な作業はログを取っておくものなので、出番は
ないかも・・
pg_xlogdump 活用方法?
pg_xlogdump -r Storage …
rmgr: Storage len (rec/tot): 16/ 48,
tx: 0, lsn: 0/0227AA20, prev 0/0227A9F0,
bkp: 0000, desc: file create: base/12297/16505
挙動を見てみよう その1
●
Btreeのリーフスプリット
●
Btreeインデックスのスプリットは
●
一番右端のリーフは左をFILLFACTORぶん詰める
●
それ以外は1:1の比率で分ける
リーフ分割
右はなるべく空ける
見てみる
create table test (c1 int);
CREATE INDEX test_idx ON test(c1);
INSERT into test SELECT generate_series(1,1000);
SELECT (bt_page_stats('test_idx', i)).blkno,(bt_page_stats('test_idx', i)).type,
(bt_page_stats('test_idx', i)).live_items, (bt_page_stats('test_idx', i)).btpo_prev,
(bt_page_stats('test_idx', i)).btpo_next FROM (SELECT generate_series(1,
relpages-1) from pg_class WHERE relname = 'test_idx')s(i);
blkno | type | live_items | btpo_prev | btpo_next
-------+------+------------+-----------+-----------
1 | l | 367 | 0 | 2
2 | l | 367 | 1 | 4
3 | r | 3 | 0 | 0
4 | l | 268 | 2 | 0
見てみる
INSERT INTO test SELECT 1 FROM generate_series(1,100);
blkno | type | live_items | btpo_prev | btpo_next
-------+------+------------+-----------+-----------
1 | l | 251 | 0 | 5
2 | l | 367 | 5 | 4
3 | r | 4 | 0 | 0
4 | l | 268 | 2 | 0
5 | l | 217 | 1 | 2
左のリーフがスプリットされ
251:217のキーを保持
見てみる
INSERT INTO test SELECT 1000 FROM generate_series(1,200);
blkno | type | live_items | btpo_prev | btpo_next
-------+------+------------+-----------+-----------
1 | l | 251 | 0 | 5
2 | l | 367 | 5 | 4
3 | r | 5 | 0 | 0
4 | l | 407 | 2 | 6
5 | l | 217 | 1 | 2
6 | l | 62 | 4 | 0
右端のリーフがスプリットされ
407:62のキーを保持
挙動を見てみよう その2
●
Commit Hint Bit
●
INSERTやUPDATEで新規のデータが投入される
●
そのトランザクションがコミットされる
●
別のトランザクションがその新規のデータを見る
●
その際、本当にコミットされたかをコミットログから判断する
●
コミットされていたらフラグを立て、以降はフラグで判断する
●
これがCommit Hint Bit
タプルヘッダ 実データTx A
Tx B
INSERT & COMMIT
clog
見に行く
Hintない
Clog見る
Commitされてた。
フラグ付ける
見てみる
●
簡単なデモで
終わりに
●
PostgreSQLのデータ構成とツールの一部を紹
介しました
●
データの作りや変更を追っていく
と、PostgreSQLの中が見えてきます
●
バイナリエディタやgdbを駆使するのもアリで
すが、便利なツールもあります
●
是非使ってみてください!
ご清聴ありがとうございました!
QA?

20140531 JPUGしくみ+アプリケーション分科会 勉強会資料