【T2】Vacuum徹底解説
Masahiko Sawada
PostgreSQL Conference Japan 2021
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
2
Vacuumは最も重要な機能の一つ
• PostgreSQL = Vacuumみたいなところもある
• 仕組みや特性を理解する
• トラブル時も慌てなくなるし、応用も効く
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
3
目次
• PostgreSQLのアーキテクチャを簡単に紹介
• なぜVacuumが必要?どうやって動くの?
• ゴミ掃除
• XID周回の防止(FREEZE)
• おすすめの設定パラメータ
• モニタリング
• トラブルシューティング&TIPS
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
4
用語説明
• ページ/ブロック
• テーブル、インデックスを構成するデータ。PostgreSQLのI/Oする単位。デフォルトでは1ページは
8kB。
• トランザクションID(XID)
• 各トランザクションに付与される単調増加する非負整数
• Visibility Map
• 各テーブルに付いているマップ。「ゴミを持つブロック」が簡単にわかる(詳細はあとで説明します)
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
5
2分でわかるPostgreSQLのアーキテクチャ
10 Alice
10
Alice
テーブル
タプル(行)
インデックス
インデックス
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
6
2分でわかるPostgreSQLのアーキテクチャ
Alice→BobにUPDATE
10 Alice
10
Alice
テーブル
タプル(行)
インデックス
10 Bob
インデックス
10
Bob
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
7
2分でわかるPostgreSQLのアーキテクチャ
VacuumでAliceのタプルを回収
テーブル
タプル(行)
インデックス
10 Bob
インデックス
10
Bob
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
8
2分でわかるPostgreSQLのアーキテクチャ
新たにCarolのタプルをINSERT
3 Carol
3
Carol
テーブル
タプル(行)
インデックス
10 Bob
インデックス
10
Bob
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
9
なぜVacuumが必要?
Vacuumが担当している役割は基本的には2つ
1. ゴミの回収
• テーブル、インデックスの肥大化を防ぐ
• Visibility Mapの更新(Vacuumの効率化+Index Only Scanの効率化)
2. XID周回の防止
• 詳しいことは後半で
• Vacuum中は両方(ゴミ回収&XID周回の防止)行う
• 起動する(=必要な)タイミングが2つある
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
10
VACUUMとVACUUM FULL
• 基本的にはVACUUMのみでOK
• 本セッションでもVACUUMに焦点を当てて説明します
ゴミを回収する XID周回の防止 テーブルを小さくする 処理中にテーブルにアクセス可能
VACUUM ○ ○ △ ○
VACUUM
FULL ○ ○ ○ ✕
ゴミ掃除
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
12
PostgreSQLのUPDATE/DELETEはゴミを残す
• UPDATEやDELETEで削除マークを付けたタプルの領域はVacuumしないと再利用できない
• 削除”マーク”なのはまだ他のトランザクションが見る可能性があるため
• ゴミはテーブルにもインデックスにも溜まるのでどちらにもVacuumが必要
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
13
HOT更新が使えるのがベスト
10 Alice
10
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
14
HOT更新が使えるのがベスト
Alice→Bobに通常の更新
10 Alice
10
10 Bob
10
テーブルにもインデックスにも
新しいタプルを挿入する
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
15
HOT更新が使えるのがベスト
10 Alice
10
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
16
HOT更新が使えるのがベスト
Alice→BobにHOT更新
10 Alice
10
10 Bob
インデックスには触らず、

テーブル内でOld→Newにリンクを作る
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
17
HOT更新が使えるのがベスト
さらにBob→CarolにHOT更新
10 Alice
10
10 Bob
インデックスには触らず、

テーブル内でOld→Newにリンクを作る
10 Carol
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
18
HOT更新が使えるのがベスト
ページ単位でVacuumが走り、リンク内のいらないタプルを回収できる
10
• インデックスにはゴミは溜まらない
• テーブル内のタプルもVACUUMなしで
(SELECT時等)回収可能
10 Carol
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
19
HOT更新を使うには条件がある
• インデックスを貼っている列を更新しないこと
• 対策:不要なインデックスは削除する
• ページ内に新しいタプルが入る分の空き領域があること
• ページを跨いだリンクは作れない
• 対策:FILLFACTORを利用する
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
20
HOT更新が使えるのがベスト・・・だけど
• HOT更新が使えれば肥大化を防げる
• ただ使える条件が色々ある(インデックスが貼ってある列を更新しないなど)
• 現実的には全ての更新をHOT更新にするのは難しい
• Vacuumも併用してゴミを回収する
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
21
自動Vacuum
• テーブル内のゴミタプル数やその割合を元に(+XID周回防止のタイミングで)自動的に起動する
• 時間帯などで制御することはできない
• 最大でautovacuum_max_workersが同時にVacuumする(Analyzeもする)
• 遅延がかかっている
• FULLじゃない。パラレルじゃない。
• 特別な要件がなければ自動Vacuumに任せるのがおすすめ
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
22
自動Vacuumのパラメータ
ゴミタプルの数や割合で自動Vacuumを起動する
• autovacuum_vacuum_threshold/scale_factor (50/0.2)
• (threshold + (全タプル数 * scale_factor))以上のゴミタプルがあるときに自動Vacuumを
起動する
• autovaucum_vacuum_insert_threshold (0.2)
• ゴミタプル数ではなく、INSERTタプル数を元に自動Vacuumを起動する
• パラメータはテーブルごとにも設定可能
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
23
ロングトランザクション
ゴミ回収の一番の敵
• 全てのトランザクションが見ないことが分かっているデータのみをゴミとして扱える
• 1つでも見る可能性のあるトランザクションがあればそれはゴミではない
• あるトランザクションが長時間実行中だと、そのトランザクションが開始以降に削除されたタプルは回収できない
• ”ロングトランザクション”とみなされるもの
• 長時間実行中のクエリ
• 次のクエリを待っているトランザクション (idle in transaction)
• 準備済み(PREPARE済み)の2相コミット
• レプリケーション(物理・論理)のスタンバイサーバで開始されたロングトランザクション
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
24
ここまでのまとめ
• HOT更新のために不要なインデックスは削除する
• 特別な要件がなければ自動Vacuumに任せる
• ゴミタプルが回収されない?と思ったら”ロングトランザクション”の存在を確認する
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
25
(すこし脱線)UNDOログとの違い
PostgreSQL Database X
UNDO
• ゴミはページ内に放置
• Vacuumは各部屋を回っ
てゴミを回収(ゴミがあ
る部屋が事前にわかる=
Visibility Map)
• ゴミじゃなかった
(ROLLBACK)場合もそ
のままでOK
• ゴミはゴミ捨て場
(UNDOログ)へ自分で
持っていく
• ゴミ捨て場にあるゴミを
捨てるだけ
• ゴミじゃなかった
(ROLLBACK)場合は部
屋に戻す必要がある
Vacuumの動き
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
27
Vacuumの動き
FULLじゃない方のVacuum
• テーブルの先頭からゴミタプルを探す
• 見つけたゴミタプルのタプルID(TID)をメモリに保存 (Scanning
heap)
• maintenance_work_mem、autovacuum_work_mem
• テーブルを見終わったら、インデックスを1つずつVacuumしてい
く (Vacuuming indexes)
• テーブルをVacuum (Vacuuming heap)
• テーブルの末尾を切り詰める (Truncating heap)
Scanning heap
Vacuuming indexes
Vacuuming heap
Cleaning up indexes
Truncating heap
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
28
最適化やオプション
• Visibility Map
• 各テーブルが持っているマップ
• ゴミを持つページが分かる
• パラレルVacuum (PostgreSQL 13 ~ )
• 複数のインデックスを並列でVacuumする
• VACUUMコマンドのオプション
• INDEX_CLEANUP, TRUNCATEなど
• インデックスVacuumやTruncateフェーズをスキップできる
Scanning heap
Vacuuming indexes
Vacuuming heap
Cleaning up indexes
Truncating heap
モニタリング
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
30
log_autovacuum_min_duration
長時間実行した自動Vacuumの活動をログに出す(デフォルト無効)
LOG: automatic vacuum of table "postgres.public.tbl": index scans: 1
pages: 0 removed, 8850 remain, 0 skipped due to pins, 0 skipped frozen
tuples: 1000000 removed, 1000000 remain, 0 are dead but not yet removable, oldest xmin: 737
index scan needed: 4425 pages from table (50.00% of total) had 1000000 dead item identifiers removed
index "tbl_pkey": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable
index "tbl_b_idx": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable
avg read rate: 7.576 MB/s, avg write rate: 13.567 MB/s
buffer usage: 27981 hits, 5184 misses, 9283 dirtied
WAL usage: 28638 records, 6 full page images, 15077678 bytes
system usage: CPU: user: 2.81 s, system: 0.15 s, elapsed: 5.34 s
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
31
log_autovacuum_min_duration
長時間実行した自動Vacuumの活動をログに出す(デフォルト無効)
LOG: automatic vacuum of table "postgres.public.tbl": index scans: 1
pages: 0 removed, 8850 remain, 0 skipped due to pins, 0 skipped frozen
tuples: 1000000 removed, 1000000 remain, 0 are dead but not yet removable, oldest xmin: 737
index scan needed: 4425 pages from table (50.00% of total) had 1000000 dead item identifiers removed
index "tbl_pkey": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable
index "tbl_b_idx": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable
avg read rate: 7.576 MB/s, avg write rate: 13.567 MB/s
buffer usage: 27981 hits, 5184 misses, 9283 dirtied
WAL usage: 28638 records, 6 full page images, 15077678 bytes
system usage: CPU: user: 2.81 s, system: 0.15 s, elapsed: 5.34 s
理想は常に「1」
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
32
log_autovacuum_min_duration
長時間実行した自動Vacuumの活動をログに出す(デフォルト無効)
LOG: automatic vacuum of table "postgres.public.tbl": index scans: 1
pages: 0 removed, 8850 remain, 0 skipped due to pins, 0 skipped frozen
tuples: 1000000 removed, 1000000 remain, 0 are dead but not yet removable, oldest xmin: 737
index scan needed: 4425 pages from table (50.00% of total) had 1000000 dead item identifiers removed
index "tbl_pkey": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable
index "tbl_b_idx": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable
avg read rate: 7.576 MB/s, avg write rate: 13.567 MB/s
buffer usage: 27981 hits, 5184 misses, 9283 dirtied
WAL usage: 28638 records, 6 full page images, 15077678 bytes
system usage: CPU: user: 2.81 s, system: 0.15 s, elapsed: 5.34 s
ロングトランザクション等で
「ゴミになりきれないタプル」は
ここにカウントされる。
少ない方が良い。
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
33
pg_stat_progress_vacuumビュー
Vacuumが今何をしているかが確認できるビュー
=# SELECT * FROM pg_stat_progress_vacuum;
-[ RECORD 1 ]———+--------------
pid | 9130
datid | 13238
datname | postgres
relid | 16384
phase | scanning heap
heap_blks_total | 8850
heap_blks_scanned | 6530
heap_blks_vacuumed | 0
index_vacuum_count | 0
max_dead_tuples | 2575350
num_dead_tuples | 475731
Scanning heap
Vacuuming indexes
Vacuuming heap
Cleaning up indexes
Truncating heap
// 現在のフェーズ
// テーブルの総ブロック数
// 何ブロックまでスキャンしたか
// 何ブロックまでVacuumしたか
// Index Vacuumの回数
// 格納できる最大のゴミタプルの数
// 現在のゴミタプルの数
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
34
pg_stat_all_tables
テーブル毎の稼働統計情報が入っている
• n_tup_upd, n_tup_hot_upd : 通常の更新とHOT更新の数
• n_dead_tup : ゴミタプルの数
• last_autovacuum, last_vacuum : 最後に(自動)Vacuumした時刻
• vacuum_count : Vacuumした回数
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
35
ここまでのまとめ
• ログはできるだけ出しておいた方が良い
• ちゃんとゴミタプルが回収されているか?
• インデックスVacuumが複数回走っていないか?
• 十分な頻度でVacuumが実行されているか?
• HOT更新はどれくらい使われているか?
XID周回の防止 ~ Freeze ~
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
37
XID周回問題
• XIDは32-bit 非負整数値(最大2^32 - 1 = 4,294,967,295)
• XIDはタプルの可視性判断に使っている
• 例)XID=100はXID=90がINSERTしたタプルは見える
• XIDが周回するとタプルの可視性判断が壊れる
• 例)XID=100はXID=(周回した後の)90のタプルは見えてはいけない
• タプル(のXIDに)Freezeマークを付けることで「XIDの値に関係なく過去」とする(=Freeze処理)
• Freezeは定期的(約21億トランザクション毎)にテーブル単位で必要
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
38
Freeze
一定量のトランザクションを消費する度にテーブル毎に定期的に必要な処理
• ゴミ回収とは別のタイミングで自動Vacuumが起動される
• 「積極的なバキューム」「aggressive vacuum」
• 通常のVacuumよりも重い
• autovacuum_freeze_xxxパラメータ等で起動タイミングを制御する
• もしFreezeがずっとされなかったら?
• 新しいXIDの払い出しが停止=データベース全体がRead-onlyになる
• DBデータが壊れる、ということはない
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
39
PostgreSQLの基本的なFreeze戦略
1.5億
2億
21億
16億
0
• テーブル毎の年齢(テーブルが作られてか
ら/FreezeされてからどれくらいXIDが消費
されたか)を管理
• テーブルが作られた直後は0歳
• トランザクションが生成されるたびに歳を
取る(約21億歳が上限)
• どれくらい古くなったかによって、Freeze
するために自動的にVacuumが起動される
• Freezeされれば若返る
Tbl1
Tbl2
Tbl3
Tbl4
次Vacuumすると
きには積極的に
Freezeするよ
Freezeするため
にVacuumを起動
するよ
Failsafeモードに
入るよ
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
40
PostgreSQLの基本的なFreeze戦略
1.5億
2億
21億
16億
0
• テーブル毎の年齢(テーブルが作られてか
ら/FreezeされてからどれくらいXIDが消費
されたか)を管理
• テーブルが作られた直後は0歳
• トランザクションが生成されるたびに歳を
取る(約21億歳が上限)
• どれくらい古くなったかによって、Freeze
するために自動的にVacuumが起動される
• Freezeされれば若返る
Tbl1
Tbl2
Tbl3
Tbl4
次Vacuumすると
きには積極的に
Freezeするよ
Freezeするため
にVacuumを起動
するよ
Failsafeモードに
入るよ
vacuum_freeze_table_age
autovacuum_freeze_max_age
vacuum_failsafe_age
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
41
Failsafeモード
PostgreSQL 14からの新機能
• 最悪な状況(Read-only化)を防ぐ機能
• 16億トランザクション消費する間に全てのテーブルの
Freeze処理が完了しなかった場合、Failsafeモードと呼ば
れるモードに入る
• Freezeすることを最優先する
• インデックスVacuumやTruncateのスキップ、遅延しない、
など
Scanning heap
Vacuuming indexes
Vacuuming heap
Cleaning up indexes
Truncating heap
トラブルシューティング&
TIPS
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
43
Vacuumしてもゴミが回収されない
• ロングトランザクションを確認する
• 長時間実行中のクエリ(pg_stat_activityのquery_start等)
• 途中で止まっているトランザクション(pg_stat_activityのstate等)
• 未完了の2相コミット(pg_prepared_xacts)
• レプリケーションのスタンバイサーバ(pg_stat_replication)
• 原因を取り除いて再度Vacuumを実行
• それでもテーブルサイズが大きくなり続ける場合は自動Vacuumが間に合ってないので、より頻度を高くするか遅延を弱くする
• テーブル・パーティショニングを検討しても良いかも
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
44
Vacuumが終わらない
• pg_stat_progress_vacuumでどこで止まっているか、なぜ遅いかを確認
• ディスクがボトルネック?遅延が効きすぎている?
• テーブルが大きすぎる→テーブル・パーティショニングを検討する
• インデックスVacuumに時間がかかっている→不要なインデックスを削除
• インデックスVacuumが何度も実行されている→maintenance_work_memが足りていない
• パラメータを設定し直して再度Vacuumをやり直すのもあり(maintenance_work_memを増やしても実行中のVacuumには効
果がない)
• 実行中のVacuumはpg_cancel_backend()でキャンセル可能(またはpg_terminate_backend())
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
45
“最速”でVacuumするには
• 遅延を無効にする(手動Vacuumではデフォルトで無効)
• maintenance_work_memを1GBに設定
• VACUUMコマンドのオプションで処理を制御
• PARALLEL N、もしくはINDEX_CLEANUP OFF
• Nはインデックス数-1。max_parallel_maintenance_workersに注意
• TRUNCATE OFF
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
46
テーブルが肥大化しすぎた
• VACUUM FULLやCLUSTERを使ってテーブルの物理サイズを小さくすることが可能
• ただし、排他ロックを取る&全インデックス再作成するので長時間なにもできなくなる
• pg_repackを使うことも検討する
• https://github.com/reorg/pg_repack
• 同時アクセスを許しながらVACUUM FULL相当のことができる
まとめ
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
48
おすすめパラメータ
• log_autovacuum_min_duration:数分くらい。ログが出すぎないよう
に
• autovacuum_max_workers:最低でも(大きいテーブルの数+2,3)はほ
しい
• max_parallel_maintenance_workers:多めでもOK。
max_worker_processesを上げるのも忘れずに
• maintenance_work_mem:デフォルトでもOK。最大で
autovacuum_max_workers個が並列で走ることに注意。巨大なテーブ
ルには大きい値を指定してもOK。
maintenance_work_mem 格納できるゴミタプル数
64MB(default) 約1100万行
256MB 約4400万行
512MB 約8900万行
1GB 約1億2000万行
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
49
今回触れていない話題
• ANALYZE、自動ANALYZE
• 遅延Vacuumのパラメータ
• マルチトランザクションID
• 各処理の細かい最適化
• Vacuumの今後の改善
© Copyright EnterpriseDB Corporation, 2021. All rights reserved.
50
最後に
• Vacuumにはゴミ掃除&XID周回の防止の2つの役割がある(起動するタイミングも2つ)
• まずはHOT更新を意識して不要なインデックスは削除する
• モニタリグしながら適宜調整していくべし
• 殆どのパラメータはテーブル単位で設定が可能
• 状況が悪くなっていることを把握する&そうなったときの対処法を用意する
• Vacuumの改善点も募集中です!
Thank you

E-mail: masahiko.sawada@enterprisedb.com

Twitter: @masahiko_sawada

Vacuum徹底解説

  • 1.
  • 2.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 2 Vacuumは最も重要な機能の一つ • PostgreSQL = Vacuumみたいなところもある • 仕組みや特性を理解する • トラブル時も慌てなくなるし、応用も効く
  • 3.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 3 目次 • PostgreSQLのアーキテクチャを簡単に紹介 • なぜVacuumが必要?どうやって動くの? • ゴミ掃除 • XID周回の防止(FREEZE) • おすすめの設定パラメータ • モニタリング • トラブルシューティング&TIPS
  • 4.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 4 用語説明 • ページ/ブロック • テーブル、インデックスを構成するデータ。PostgreSQLのI/Oする単位。デフォルトでは1ページは 8kB。 • トランザクションID(XID) • 各トランザクションに付与される単調増加する非負整数 • Visibility Map • 各テーブルに付いているマップ。「ゴミを持つブロック」が簡単にわかる(詳細はあとで説明します)
  • 5.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 5 2分でわかるPostgreSQLのアーキテクチャ 10 Alice 10 Alice テーブル タプル(行) インデックス インデックス
  • 6.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 6 2分でわかるPostgreSQLのアーキテクチャ Alice→BobにUPDATE 10 Alice 10 Alice テーブル タプル(行) インデックス 10 Bob インデックス 10 Bob
  • 7.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 7 2分でわかるPostgreSQLのアーキテクチャ VacuumでAliceのタプルを回収 テーブル タプル(行) インデックス 10 Bob インデックス 10 Bob
  • 8.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 8 2分でわかるPostgreSQLのアーキテクチャ 新たにCarolのタプルをINSERT 3 Carol 3 Carol テーブル タプル(行) インデックス 10 Bob インデックス 10 Bob
  • 9.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 9 なぜVacuumが必要? Vacuumが担当している役割は基本的には2つ 1. ゴミの回収 • テーブル、インデックスの肥大化を防ぐ • Visibility Mapの更新(Vacuumの効率化+Index Only Scanの効率化) 2. XID周回の防止 • 詳しいことは後半で • Vacuum中は両方(ゴミ回収&XID周回の防止)行う • 起動する(=必要な)タイミングが2つある
  • 10.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 10 VACUUMとVACUUM FULL • 基本的にはVACUUMのみでOK • 本セッションでもVACUUMに焦点を当てて説明します ゴミを回収する XID周回の防止 テーブルを小さくする 処理中にテーブルにアクセス可能 VACUUM ○ ○ △ ○ VACUUM FULL ○ ○ ○ ✕
  • 11.
  • 12.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 12 PostgreSQLのUPDATE/DELETEはゴミを残す • UPDATEやDELETEで削除マークを付けたタプルの領域はVacuumしないと再利用できない • 削除”マーク”なのはまだ他のトランザクションが見る可能性があるため • ゴミはテーブルにもインデックスにも溜まるのでどちらにもVacuumが必要
  • 13.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 13 HOT更新が使えるのがベスト 10 Alice 10
  • 14.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 14 HOT更新が使えるのがベスト Alice→Bobに通常の更新 10 Alice 10 10 Bob 10 テーブルにもインデックスにも 新しいタプルを挿入する
  • 15.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 15 HOT更新が使えるのがベスト 10 Alice 10
  • 16.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 16 HOT更新が使えるのがベスト Alice→BobにHOT更新 10 Alice 10 10 Bob インデックスには触らず、
 テーブル内でOld→Newにリンクを作る
  • 17.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 17 HOT更新が使えるのがベスト さらにBob→CarolにHOT更新 10 Alice 10 10 Bob インデックスには触らず、
 テーブル内でOld→Newにリンクを作る 10 Carol
  • 18.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 18 HOT更新が使えるのがベスト ページ単位でVacuumが走り、リンク内のいらないタプルを回収できる 10 • インデックスにはゴミは溜まらない • テーブル内のタプルもVACUUMなしで (SELECT時等)回収可能 10 Carol
  • 19.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 19 HOT更新を使うには条件がある • インデックスを貼っている列を更新しないこと • 対策:不要なインデックスは削除する • ページ内に新しいタプルが入る分の空き領域があること • ページを跨いだリンクは作れない • 対策:FILLFACTORを利用する
  • 20.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 20 HOT更新が使えるのがベスト・・・だけど • HOT更新が使えれば肥大化を防げる • ただ使える条件が色々ある(インデックスが貼ってある列を更新しないなど) • 現実的には全ての更新をHOT更新にするのは難しい • Vacuumも併用してゴミを回収する
  • 21.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 21 自動Vacuum • テーブル内のゴミタプル数やその割合を元に(+XID周回防止のタイミングで)自動的に起動する • 時間帯などで制御することはできない • 最大でautovacuum_max_workersが同時にVacuumする(Analyzeもする) • 遅延がかかっている • FULLじゃない。パラレルじゃない。 • 特別な要件がなければ自動Vacuumに任せるのがおすすめ
  • 22.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 22 自動Vacuumのパラメータ ゴミタプルの数や割合で自動Vacuumを起動する • autovacuum_vacuum_threshold/scale_factor (50/0.2) • (threshold + (全タプル数 * scale_factor))以上のゴミタプルがあるときに自動Vacuumを 起動する • autovaucum_vacuum_insert_threshold (0.2) • ゴミタプル数ではなく、INSERTタプル数を元に自動Vacuumを起動する • パラメータはテーブルごとにも設定可能
  • 23.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 23 ロングトランザクション ゴミ回収の一番の敵 • 全てのトランザクションが見ないことが分かっているデータのみをゴミとして扱える • 1つでも見る可能性のあるトランザクションがあればそれはゴミではない • あるトランザクションが長時間実行中だと、そのトランザクションが開始以降に削除されたタプルは回収できない • ”ロングトランザクション”とみなされるもの • 長時間実行中のクエリ • 次のクエリを待っているトランザクション (idle in transaction) • 準備済み(PREPARE済み)の2相コミット • レプリケーション(物理・論理)のスタンバイサーバで開始されたロングトランザクション
  • 24.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 24 ここまでのまとめ • HOT更新のために不要なインデックスは削除する • 特別な要件がなければ自動Vacuumに任せる • ゴミタプルが回収されない?と思ったら”ロングトランザクション”の存在を確認する
  • 25.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 25 (すこし脱線)UNDOログとの違い PostgreSQL Database X UNDO • ゴミはページ内に放置 • Vacuumは各部屋を回っ てゴミを回収(ゴミがあ る部屋が事前にわかる= Visibility Map) • ゴミじゃなかった (ROLLBACK)場合もそ のままでOK • ゴミはゴミ捨て場 (UNDOログ)へ自分で 持っていく • ゴミ捨て場にあるゴミを 捨てるだけ • ゴミじゃなかった (ROLLBACK)場合は部 屋に戻す必要がある
  • 26.
  • 27.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 27 Vacuumの動き FULLじゃない方のVacuum • テーブルの先頭からゴミタプルを探す • 見つけたゴミタプルのタプルID(TID)をメモリに保存 (Scanning heap) • maintenance_work_mem、autovacuum_work_mem • テーブルを見終わったら、インデックスを1つずつVacuumしてい く (Vacuuming indexes) • テーブルをVacuum (Vacuuming heap) • テーブルの末尾を切り詰める (Truncating heap) Scanning heap Vacuuming indexes Vacuuming heap Cleaning up indexes Truncating heap
  • 28.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 28 最適化やオプション • Visibility Map • 各テーブルが持っているマップ • ゴミを持つページが分かる • パラレルVacuum (PostgreSQL 13 ~ ) • 複数のインデックスを並列でVacuumする • VACUUMコマンドのオプション • INDEX_CLEANUP, TRUNCATEなど • インデックスVacuumやTruncateフェーズをスキップできる Scanning heap Vacuuming indexes Vacuuming heap Cleaning up indexes Truncating heap
  • 29.
  • 30.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 30 log_autovacuum_min_duration 長時間実行した自動Vacuumの活動をログに出す(デフォルト無効) LOG: automatic vacuum of table "postgres.public.tbl": index scans: 1 pages: 0 removed, 8850 remain, 0 skipped due to pins, 0 skipped frozen tuples: 1000000 removed, 1000000 remain, 0 are dead but not yet removable, oldest xmin: 737 index scan needed: 4425 pages from table (50.00% of total) had 1000000 dead item identifiers removed index "tbl_pkey": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable index "tbl_b_idx": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable avg read rate: 7.576 MB/s, avg write rate: 13.567 MB/s buffer usage: 27981 hits, 5184 misses, 9283 dirtied WAL usage: 28638 records, 6 full page images, 15077678 bytes system usage: CPU: user: 2.81 s, system: 0.15 s, elapsed: 5.34 s
  • 31.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 31 log_autovacuum_min_duration 長時間実行した自動Vacuumの活動をログに出す(デフォルト無効) LOG: automatic vacuum of table "postgres.public.tbl": index scans: 1 pages: 0 removed, 8850 remain, 0 skipped due to pins, 0 skipped frozen tuples: 1000000 removed, 1000000 remain, 0 are dead but not yet removable, oldest xmin: 737 index scan needed: 4425 pages from table (50.00% of total) had 1000000 dead item identifiers removed index "tbl_pkey": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable index "tbl_b_idx": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable avg read rate: 7.576 MB/s, avg write rate: 13.567 MB/s buffer usage: 27981 hits, 5184 misses, 9283 dirtied WAL usage: 28638 records, 6 full page images, 15077678 bytes system usage: CPU: user: 2.81 s, system: 0.15 s, elapsed: 5.34 s 理想は常に「1」
  • 32.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 32 log_autovacuum_min_duration 長時間実行した自動Vacuumの活動をログに出す(デフォルト無効) LOG: automatic vacuum of table "postgres.public.tbl": index scans: 1 pages: 0 removed, 8850 remain, 0 skipped due to pins, 0 skipped frozen tuples: 1000000 removed, 1000000 remain, 0 are dead but not yet removable, oldest xmin: 737 index scan needed: 4425 pages from table (50.00% of total) had 1000000 dead item identifiers removed index "tbl_pkey": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable index "tbl_b_idx": pages: 5486 in total, 0 newly deleted, 0 currently deleted, 0 reusable avg read rate: 7.576 MB/s, avg write rate: 13.567 MB/s buffer usage: 27981 hits, 5184 misses, 9283 dirtied WAL usage: 28638 records, 6 full page images, 15077678 bytes system usage: CPU: user: 2.81 s, system: 0.15 s, elapsed: 5.34 s ロングトランザクション等で 「ゴミになりきれないタプル」は ここにカウントされる。 少ない方が良い。
  • 33.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 33 pg_stat_progress_vacuumビュー Vacuumが今何をしているかが確認できるビュー =# SELECT * FROM pg_stat_progress_vacuum; -[ RECORD 1 ]———+-------------- pid | 9130 datid | 13238 datname | postgres relid | 16384 phase | scanning heap heap_blks_total | 8850 heap_blks_scanned | 6530 heap_blks_vacuumed | 0 index_vacuum_count | 0 max_dead_tuples | 2575350 num_dead_tuples | 475731 Scanning heap Vacuuming indexes Vacuuming heap Cleaning up indexes Truncating heap // 現在のフェーズ // テーブルの総ブロック数 // 何ブロックまでスキャンしたか // 何ブロックまでVacuumしたか // Index Vacuumの回数 // 格納できる最大のゴミタプルの数 // 現在のゴミタプルの数
  • 34.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 34 pg_stat_all_tables テーブル毎の稼働統計情報が入っている • n_tup_upd, n_tup_hot_upd : 通常の更新とHOT更新の数 • n_dead_tup : ゴミタプルの数 • last_autovacuum, last_vacuum : 最後に(自動)Vacuumした時刻 • vacuum_count : Vacuumした回数
  • 35.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 35 ここまでのまとめ • ログはできるだけ出しておいた方が良い • ちゃんとゴミタプルが回収されているか? • インデックスVacuumが複数回走っていないか? • 十分な頻度でVacuumが実行されているか? • HOT更新はどれくらい使われているか?
  • 36.
  • 37.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 37 XID周回問題 • XIDは32-bit 非負整数値(最大2^32 - 1 = 4,294,967,295) • XIDはタプルの可視性判断に使っている • 例)XID=100はXID=90がINSERTしたタプルは見える • XIDが周回するとタプルの可視性判断が壊れる • 例)XID=100はXID=(周回した後の)90のタプルは見えてはいけない • タプル(のXIDに)Freezeマークを付けることで「XIDの値に関係なく過去」とする(=Freeze処理) • Freezeは定期的(約21億トランザクション毎)にテーブル単位で必要
  • 38.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 38 Freeze 一定量のトランザクションを消費する度にテーブル毎に定期的に必要な処理 • ゴミ回収とは別のタイミングで自動Vacuumが起動される • 「積極的なバキューム」「aggressive vacuum」 • 通常のVacuumよりも重い • autovacuum_freeze_xxxパラメータ等で起動タイミングを制御する • もしFreezeがずっとされなかったら? • 新しいXIDの払い出しが停止=データベース全体がRead-onlyになる • DBデータが壊れる、ということはない
  • 39.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 39 PostgreSQLの基本的なFreeze戦略 1.5億 2億 21億 16億 0 • テーブル毎の年齢(テーブルが作られてか ら/FreezeされてからどれくらいXIDが消費 されたか)を管理 • テーブルが作られた直後は0歳 • トランザクションが生成されるたびに歳を 取る(約21億歳が上限) • どれくらい古くなったかによって、Freeze するために自動的にVacuumが起動される • Freezeされれば若返る Tbl1 Tbl2 Tbl3 Tbl4 次Vacuumすると きには積極的に Freezeするよ Freezeするため にVacuumを起動 するよ Failsafeモードに 入るよ
  • 40.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 40 PostgreSQLの基本的なFreeze戦略 1.5億 2億 21億 16億 0 • テーブル毎の年齢(テーブルが作られてか ら/FreezeされてからどれくらいXIDが消費 されたか)を管理 • テーブルが作られた直後は0歳 • トランザクションが生成されるたびに歳を 取る(約21億歳が上限) • どれくらい古くなったかによって、Freeze するために自動的にVacuumが起動される • Freezeされれば若返る Tbl1 Tbl2 Tbl3 Tbl4 次Vacuumすると きには積極的に Freezeするよ Freezeするため にVacuumを起動 するよ Failsafeモードに 入るよ vacuum_freeze_table_age autovacuum_freeze_max_age vacuum_failsafe_age
  • 41.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 41 Failsafeモード PostgreSQL 14からの新機能 • 最悪な状況(Read-only化)を防ぐ機能 • 16億トランザクション消費する間に全てのテーブルの Freeze処理が完了しなかった場合、Failsafeモードと呼ば れるモードに入る • Freezeすることを最優先する • インデックスVacuumやTruncateのスキップ、遅延しない、 など Scanning heap Vacuuming indexes Vacuuming heap Cleaning up indexes Truncating heap
  • 42.
  • 43.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 43 Vacuumしてもゴミが回収されない • ロングトランザクションを確認する • 長時間実行中のクエリ(pg_stat_activityのquery_start等) • 途中で止まっているトランザクション(pg_stat_activityのstate等) • 未完了の2相コミット(pg_prepared_xacts) • レプリケーションのスタンバイサーバ(pg_stat_replication) • 原因を取り除いて再度Vacuumを実行 • それでもテーブルサイズが大きくなり続ける場合は自動Vacuumが間に合ってないので、より頻度を高くするか遅延を弱くする • テーブル・パーティショニングを検討しても良いかも
  • 44.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 44 Vacuumが終わらない • pg_stat_progress_vacuumでどこで止まっているか、なぜ遅いかを確認 • ディスクがボトルネック?遅延が効きすぎている? • テーブルが大きすぎる→テーブル・パーティショニングを検討する • インデックスVacuumに時間がかかっている→不要なインデックスを削除 • インデックスVacuumが何度も実行されている→maintenance_work_memが足りていない • パラメータを設定し直して再度Vacuumをやり直すのもあり(maintenance_work_memを増やしても実行中のVacuumには効 果がない) • 実行中のVacuumはpg_cancel_backend()でキャンセル可能(またはpg_terminate_backend())
  • 45.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 45 “最速”でVacuumするには • 遅延を無効にする(手動Vacuumではデフォルトで無効) • maintenance_work_memを1GBに設定 • VACUUMコマンドのオプションで処理を制御 • PARALLEL N、もしくはINDEX_CLEANUP OFF • Nはインデックス数-1。max_parallel_maintenance_workersに注意 • TRUNCATE OFF
  • 46.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 46 テーブルが肥大化しすぎた • VACUUM FULLやCLUSTERを使ってテーブルの物理サイズを小さくすることが可能 • ただし、排他ロックを取る&全インデックス再作成するので長時間なにもできなくなる • pg_repackを使うことも検討する • https://github.com/reorg/pg_repack • 同時アクセスを許しながらVACUUM FULL相当のことができる
  • 47.
  • 48.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 48 おすすめパラメータ • log_autovacuum_min_duration:数分くらい。ログが出すぎないよう に • autovacuum_max_workers:最低でも(大きいテーブルの数+2,3)はほ しい • max_parallel_maintenance_workers:多めでもOK。 max_worker_processesを上げるのも忘れずに • maintenance_work_mem:デフォルトでもOK。最大で autovacuum_max_workers個が並列で走ることに注意。巨大なテーブ ルには大きい値を指定してもOK。 maintenance_work_mem 格納できるゴミタプル数 64MB(default) 約1100万行 256MB 約4400万行 512MB 約8900万行 1GB 約1億2000万行
  • 49.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 49 今回触れていない話題 • ANALYZE、自動ANALYZE • 遅延Vacuumのパラメータ • マルチトランザクションID • 各処理の細かい最適化 • Vacuumの今後の改善
  • 50.
    © Copyright EnterpriseDBCorporation, 2021. All rights reserved. 50 最後に • Vacuumにはゴミ掃除&XID周回の防止の2つの役割がある(起動するタイミングも2つ) • まずはHOT更新を意識して不要なインデックスは削除する • モニタリグしながら適宜調整していくべし • 殆どのパラメータはテーブル単位で設定が可能 • 状況が悪くなっていることを把握する&そうなったときの対処法を用意する • Vacuumの改善点も募集中です!
  • 51.