PolarDB for PostgreSQL (Compatible with Oracle) は、ストレージレイヤーとして PolarFileSystem (PFS) を採用しています。PFS は標準ファイルシステムとは異なり、大規模な連続読み取りに最適化されていますが、小規模かつ頻繁なページ拡張には高いオーバーヘッドを伴います。このような I/O 特性に対応するため、PolarDB では「ヒープテーブルの読み取り先読み」「ヒープテーブルの事前拡張」「インデックス作成時の事前拡張」の 3 つの最適化機能を導入しており、すべてデフォルトで有効です。これらの機能により、連続スキャンおよび VACUUM のスループットが 2 倍~3 倍に向上し、データロードのスループットが 2 倍に向上し、インデックス作成速度が 30 % 向上します。
前提条件
開始する前に、クラスターが以下の要件を満たしていることを確認してください。
PolarDB for PostgreSQL (Compatible with Oracle) 2.0、リビジョンバージョン 2.0.14.5.1.0 以降
リビジョンバージョンを確認するには、以下のコマンドを実行します。
SHOW polardb_version;または、PolarDB コンソールからバージョンを確認することもできます。アップグレードが必要な場合は、「バージョンのアップグレード」をご参照ください。
概要
PostgreSQL では、データの読み取りおよび書き込みが 8 KB のページ単位で行われます。標準ファイルシステムでは、このような小規模な操作が効率的に処理されますが、PFS には 8 KB 操作を高コストにする 2 つの制約があります。
PFS では、ページ拡張ごとに高いメタデータオーバーヘッドが発生します。
PFS では、ページ拡張サイズが 4 MB の倍数である必要があります。
PostgreSQL では、ページ拡張の最小サイズが 8 MB の倍数である必要がありますが、これは PFS と互換性がなく、テーブルへの書き込みやインデックス作成時にパフォーマンスが低下します。
また、8 KB 単位でのデータ読み取りも PFS 上では非効率であり、PFS は大規模な連続読み取りで最も高いパフォーマンスを発揮します。
この 3 つの機能は、上記の制約に対処するために設計されています。
| 機能 | アドレス | デフォルトパラメーター | デフォルト値 | パフォーマンスへの影響 |
|---|---|---|---|---|
| ヒープテーブルの読み取り先読み | 連続スキャン、VACUUM、インデックス作成 | polar_bulk_read_size | 128 KB | VACUUM および連続スキャンで 2 倍~3 倍、インデックス作成で +18 % |
| ヒープテーブルの事前拡張 | データロードおよび頻繁な書き込み | polar_heap_bulk_extend_size | 4 MB | データロードで 2 倍 |
| インデックス作成時の事前拡張 | B-tree、GIN、GiST、SP-GiST、Bloom インデックスの作成 | polar_index_bulk_extend_size | 4 MB | インデックス作成で +30 % |
上記の 3 つの機能はすべてデフォルトで有効です。デフォルト値は PFS に最適化されており、パフォーマンスの上限を示しています。これらの値を超えて増加させても、さらなるパフォーマンス向上は見られません。特定の運用上の理由がある場合を除き、機能を無効化しないでください。
仕組み
ヒープテーブルの読み取り先読み
PostgreSQL では通常、8 KB のページを 1 ページずつバッファープールに読み込みます。しかし、PFS 上ではこのような小規模な読み取りパターンは非効率です。2 ページ以上を読み込む必要がある場合、PolarDB ではそれらを 128 KB の単一読み取りにまとめて処理し、I/O 操作の総数を削減します。
この処理は以下の 4 ステップで実行されます。
バッファープールから N 個のバッファーを確保します。
N × page sizeのサイズの隣接したメモリ領域をpallocを使用して確保し、これをpと呼びます。PFS を使用して、ヒープテーブルから
N × page sizeのデータをpに読み込みます。pから N 個のページを N 個のバッファーにコピーします。
その後、これらのページに対する読み取りはバッファープールから直接ヒットするため、追加のディスク I/O は発生しません。
以下の図は、データフローを示しています。
ヒープテーブルの事前拡張
標準 PostgreSQL では、表領域の拡張は 8 KB のページを 1 ページずつ適用・拡張します。バッチ拡張であっても、N ページの拡張には依然として N 回の I/O 操作が必要です。PFS では最小拡張サイズが 4 MB であるため、この方式では過剰な I/O オーバーヘッドが発生します。
ヒープテーブルの事前拡張は、PFS のバルク書き込みインターフェイスを用いて 4 MB 単位でファイルを拡張することで、この問題を解決します。この処理は以下の 3 ステップで実行されます。
ファイルシステムの拡張をトリガーせずに、バッファープールから N 個のバッファーを確保します。
PFS のファイル書き込みインターフェイスを使用して、ゼロ埋めされたページを 1 回のバッチ書き込みでファイルを拡張します。
ページを 1 ページずつ初期化し、利用可能な領域を特定して、事前拡張を終了します。
インデックス作成時の事前拡張
インデックス作成時の事前拡張は、ヒープテーブルの事前拡張と同様のアプローチを採用しますが、インデックスはディスクにフラッシュされる前にバッファープール内で構築されるため、バッファー確保のステップをスキップします。
この処理は以下の 2 ステップで実行されます。
PFS のファイル書き込みインターフェイスを使用して、ゼロ埋めされたページを 1 回のバッチ書き込みでファイルを拡張します。
バッファープール内で構築されたインデックスページをファイルシステムに書き込みます。
サポートされるインデックスタイプ:B-tree、GIN、GiST、SP-GiST、Bloom。
旧バージョンの PolarDB for PostgreSQL (Compatible with Oracle) では、インデックス作成時の事前拡張は B-tree インデックスのみをサポートしていました。
読み取り先読みおよび事前拡張の設定
ヒープテーブルの読み取り先読み
polar_bulk_read_size パラメーターでヒープテーブルの読み取り先読みを制御します。デフォルト値は 128 KB であり、これは PFS に対して最適な値です。128 KB を超えて増加させても、さらなるパフォーマンス向上は見られません。
ヒープテーブルの先読みを無効化するには:
ALTER SYSTEM SET polar_bulk_read_size = 0;
SELECT pg_reload_conf();デフォルトサイズでヒープテーブルの読み取り先読みを再有効化するには、以下のコマンドを実行します。
ALTER SYSTEM SET polar_bulk_read_size = '128 KB';
SELECT pg_reload_conf();現在の値を確認するには:
SHOW polar_bulk_read_size;ヒープテーブルの事前拡張
polar_heap_bulk_extend_size パラメーターでヒープテーブルの事前拡張を制御します。デフォルト値は 4 MB であり、これは PFS に対して最適な値です。4 MB を超えて増加させても、さらなるパフォーマンス向上は見られません。
旧バージョンの PolarDB for PostgreSQL (Compatible with Oracle) では、対応するパラメーターは polar_bulk_extend_size です。ヒープテーブルの事前拡張を無効化するには、以下のコマンドを実行します。
ALTER SYSTEM SET polar_heap_bulk_extend_size = 0;
SELECT pg_reload_conf();デフォルトサイズでヒープテーブルの事前拡張を再有効化するには、以下のコマンドを実行します。
ALTER SYSTEM SET polar_heap_bulk_extend_size = '4 MB';
SELECT pg_reload_conf();現在の値を確認するには:
SHOW polar_heap_bulk_extend_size;インデックス作成時の事前拡張
polar_index_bulk_extend_size パラメーターでインデックス作成時の事前拡張を制御します。デフォルト値は 4 MB であり、これは PFS に対して最適な値です。4 MB を超えて増加させても、さらなるパフォーマンス向上は見られません。
旧バージョンの PolarDB for PostgreSQL (Compatible with Oracle) では、対応するパラメーターは polar_index_create_bulk_extend_size です。これらのバージョンでは、B-tree インデックスのみがサポートされていました。インデックスの作成を拡張前に無効化するには:
ALTER SYSTEM SET polar_index_bulk_extend_size = 0;
SELECT pg_reload_conf();デフォルトサイズでインデックス作成時の事前拡張を再有効化するには、以下のコマンドを実行します。
ALTER SYSTEM SET polar_index_bulk_extend_size = '4 MB';
SELECT pg_reload_conf();現在の値を確認するには:
SHOW polar_index_bulk_extend_size;パフォーマンスベンチマーク
以下のベンチマークは、PostgreSQL 14 を実行中の PolarDB for PostgreSQL (Compatible with Oracle) クラスター(8 コア、32 GB メモリ)で、400 GB の pgbench データセットを用いて測定されました。
ヒープテーブルの読み取り先読み
400 GB のテーブルにおける VACUUM のパフォーマンス比較:

400 GB のテーブルにおける連続スキャンのパフォーマンス比較:

結論:
ヒープテーブルの読み取り先読みにより、VACUUM および連続スキャンのパフォーマンスが 2 倍~3 倍に向上します。
polar_bulk_read_sizeをデフォルトの 128 KB を超えて増加させても、さらなるパフォーマンス向上は見られません。
ヒープテーブルの事前拡張
400 GB のテーブルにおけるデータロードのパフォーマンス比較:

結論:
ヒープテーブルの事前拡張により、データロードのパフォーマンスが 2 倍に向上します。
polar_heap_bulk_extend_sizeをデフォルトの 4 MB を超えて増加させても、さらなるパフォーマンス向上は見られません。
インデックス作成時の事前拡張
400 GB のテーブルにおけるインデックス作成のパフォーマンス比較:

結論:
インデックス作成時の事前拡張により、インデックス作成のパフォーマンスが 30 % 向上します。
polar_index_bulk_extend_sizeをデフォルトの 4 MB を超えて増加させても、さらなるパフォーマンス向上は見られません。