Skip to main content
Copyright©2019 NTT corp. All Rights Reserved.
PostgreSQL 12は ここがスゴイ!
~性能改善やpluggable storage engineなどの新機能を徹底解説~
澤田 雅彦
NTT OSSセンタ
NTTデータ テクノロジーカンファレンス 2019 (2019/9/5)
Copyright©2019 NTT corp. All Rights Reserved.
2018/7/1 開発開始
2019/4/1 Feature Freeze
2019/5/23 Beta 1
2019/6/20 Beta 2
2019/8/8 Beta 3
2019/9/X RC?
2019/10/X GA?
12のリリースと同時に9.4の
コミュニティサポートが終わることに注意
2
PostgreSQL 12
Copyright©2019 NTT corp. All Rights Reserved.
既存機能の大幅な改善や、
将来の機能拡張への基盤、
かゆい所に手が届くような機能が揃っている、
PostgreSQLの総合力が上がったバージョン。
ただ非互換に注意!
3
PostgreSQL 12はどんなバージョン?
Copyright©2019 NTT corp. All Rights Reserved.
約180個の新機能
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• Generated Columns(生成列)
• 非互換
4
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
5
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
PostgreSQL 12でもテーブル・パーティショニングの改善は多い(全体の約
15%、PG11もほぼ同じ)
新機能一覧
• パーティション・プルーニングの性能改善
• パーティション・テーブルへの外部キー制約の実現
• パーティション・テーブルへのCOPYの性能改善
• ATTACH PARTITIONのロックが弱くなった
– UPDATE/DELETE/INSERTと競合しなくなった
• pg_partition_root(), pg_partition_ancestors()
• パーティション境界に式を指定(テーブル作成時に評価)
6
テーブル・パーティショニングの改善
Copyright©2019 NTT corp. All Rights Reserved. 7
プランニング時間
PostgreSQL11の新機能紹介より
PostgreSQL10に
比べて早くなっている。
けど、まだプラン生成
時間が子テーブル数に
比例して伸びている
Copyright©2019 NTT corp. All Rights Reserved.
• これまでは、プランナは内部で使用するテーブルの管理情報(RangeTblEntry,
RelOptInfo)を全ての子テーブルについて作成してた。
• PG12では、プルーニング情報を求めた後に興味のある子テーブルだけの管理情
報を作成するようにした。
• 数千規模の子テーブルがある場合に有用
8
子テーブルが多い時のプラン生成時間が大幅に改善
0
20
40
60
80
100
120
50 100 500 1000 2000 5000 10000
実行計画作成時間(MS)
子テーブル数
プラン生成時間(Range Partitioning)
PG12 PG11 PG10
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
9
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• WITH句で指定したクエリ結果を一時テーブルみたいな形で扱うことがで
きる
– 複雑なSQLをより単純な部品に分解することで、SQLを読みやすくできる
• 再帰SQLのときにも使う
• PostgreSQLの実装では常にCTEの結果を一時テーブルとして持つ
– work_memを使用
– クエリの意味は同じでもsubselectを使った時とは実行計画を異なる
• MySQLも8.0からサポート
10
Common Table Expression (CTE)
Copyright©2019 NTT corp. All Rights Reserved.
-- CTEを利用(PG11まで)
=# EXPLAIN
WITH test AS (SELECT * FROM a WHERE c = 1)
SELECT * FROM test WHERE d = 1;
QUERY PLAN
------------------------------------------------------------------------
CTE Scan on test (cost=8.17..8.20 rows=1 width=8)
Filter: (d = 1)
CTE test
-> Index Scan using a_pkey on a (cost=0.15..8.17 rows=1 width=8)
Index Cond: (c = 1)
(5 rows)
11
CTEとSubSelect - PostgreSQL 11まで -
-- SubSelectを利用
=# EXPLAIN
SELECT * FROM (SELECT * FROM a WHERE c = 1 and d = 1) as test;
QUERY PLAN
----------------------------------------------------------------
Index Scan using a_pkey on a (cost=0.15..8.17 rows=1 width=8)
Index Cond: (c = 1)
Filter: (d = 1)
(3 rows)
Copyright©2019 NTT corp. All Rights Reserved.
-- CTEを利用(PG12)
=# EXPLAIN
WITH test AS (SELECT * FROM a WHERE c = 1)
SELECT * FROM test WHERE d = 1;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using a_pkey on a (cost=0.15..8.17 rows=1 width=8)
Index Cond: (c = 1)
Filter: (d = 1)
(3 rows)
12
CTEとSubSelect - PostgreSQL 12から -
-- SubSelectを利用
=# EXPLAIN
SELECT * FROM (SELECT * FROM a WHERE c = 1 and d = 1) as test;
QUERY PLAN
----------------------------------------------------------------
Index Scan using a_pkey on a (cost=0.15..8.17 rows=1 width=8)
Index Cond: (c = 1)
Filter: (d = 1)
(3 rows)
Copyright©2019 NTT corp. All Rights Reserved.
• デフォルトでCTEのクエリを展開するようになった(CTE inlining)
– 他のRDBMSもこっちの動作がデフォルトになっている
– ただし再帰SQL、SELECT以外、volatile関数が入っている場合は強制的に
MATERIALIZE(一時テーブル的な扱い)される
• [ NOT ] MATERIALIZED句で動作を制御可能
13
PostgreSQL 12以降のCTE
=# EXPLAIN
WITH test AS MATERIALIZED (SELECT * FROM a WHERE c = 1)
SELECT * FROM test WHERE d = 1;
QUERY PLAN
------------------------------------------------------------------------
CTE Scan on test (cost=8.17..8.20 rows=1 width=8)
Filter: (d = 1)
CTE test
-> Index Scan using a_pkey on a (cost=0.15..8.17 rows=1 width=8)
Index Cond: (c = 1)
(5 rows)
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
14
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• テーブルのスキャン、VACUUMは最適化済み
• インデックスのVACUUM、末尾の切り詰めは依然時間がかかる
• INDEX_CLEANUP、TRUNCATEでVACUUM処理の細かい制御が可能
– (テーブルの特性に応じて)時間がかかる処理をスキップできるようになった
Vacuumの改善
テーブル
スキャン
インデックス
VACUUM
テーブル
VACUUM
末尾の
切り詰め
長時間化に注意
1行でもゴミがあれば、
インデックスをフルスキャン
長時間化に注意
共有バッファをフルスキャン
Visibility Mapで
ゴミがあるページ
のみをスキャン
15
ゴミがあるページ
のみをVACUUM
Copyright©2019 NTT corp. All Rights Reserved.
• SKIP_LOCKED [ boolean ]
– すでにロックされているテーブルをスキップする
• TRUNCATE [ boolean ]
– テーブルの切り詰めを行わない
– 共有バッファのフルスキャンを回避
– テーブル毎に設定可能
• INDEX_CLEANUP [ boolean ]
– インデックスのVACUUMを行わない
– インデックスのVACUUMは常にフルスキャン
– テーブル毎に設定可能
16
Vacuumの改善 - 新オプション -
Copyright©2019 NTT corp. All Rights Reserved.
• TRUNCATEオプション
– テーブルの物理サイズが小さくならない
– こういう時に「TRUNCATE false」を検討する
• 高頻度で更新されるテーブル(一括削除とかがない=末尾の切り詰めが期待できない)
• 共有バッファが大きい(数百GB)
• ホットスタンバイでの競合を避けたい
• INDEX_CLEANUPオプション
– インデックスが肥大化する可能性がある
• インデックスはテーブルよりも肥大化しにくい
• REINDEX CONCURRENTLYでオンラインでShrinkすることも可能
– こういう時に「INDEX_CLEANUP false」を検討する
• 大規模テーブルで頻繁に更新がかかる
• 定期的にREINDEXできる時間がある
17
注意点と使い所
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
18
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• 他の列情報から計算式によって値を生成する列
• PG 12ではSTOREDのみ対応
– VIRTUALは未対応
• テーブル定義時に列に計算式を指定
• 行の書き込み時に計算式から算出されたデータが列に格納さ
れる
19
Generated Columns(生成列)
Copyright©2019 NTT corp. All Rights Reserved.
=# CREATE TABLE people (
height_m numeric,
weight_kg numeric,
bmi numeric
GENERATED ALWAYS AS
(weight_kg / pow(height_m, 2)) STORED
);
=# INSERT INTO people VALUES (1.7, 65);
=# SELECT * FROM people;
height_m | weight_kg | bmi
----------+-----------+---------------------
1.7 | 65 | 22.4913494809688581
(1 row)
=# UPDATE people SET weight_kg = 60;
=# SELECT * FROM people ;
height_m | weight_kg | bmi
----------+-----------+---------------------
1.8 | 60 | 20.7612456747404844
(1 row)
20
Generated Columns(生成列)
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
21
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• XpathのJSON版
• SQL 2016
• JSONデータから特定の部分を指定し、抽出するための構文
(言語)
• jsonb型のデータに対してのみ利用可能
– json型は非対応
• jsonb_path_exists(target jsonb, path jsonpath)
• jsonb_path_match(target jsonb, path jsonpath)
• jsonb_path_query(target jsonb, path jsonpath)
• jsonb_path_query_array(target jsonb, path jsonpath)
• jsonb_path_query_first(target jsonb, path jsonpath)
22
SQL/JSON path
Copyright©2019 NTT corp. All Rights Reserved.
{
“data1”: {
“a”: [1,2,3],
“b”: {
“c”: “cc”
}
},
“data2”: “d”
}
23
‘$.data1’
jsonb_path_query
------------------------------------
{"a": [1, 2, 3], "b": {"c": "cc"}}
(1 row)
Copyright©2019 NTT corp. All Rights Reserved.
{
“data1”: {
“a”: [1,2,3],
“b”: {
“c”: “cc”
}
},
“data2”: “d”
}
24
‘$.data1.a’
jsonb_path_query
------------------
[1, 2, 3]
(1 row)
Copyright©2019 NTT corp. All Rights Reserved.
{
“data1”: {
“a”: [1,2,3],
“b”: {
“c”: “cc”
}
},
“data2”: “d”
}
25
‘$.data1.a[1]’
jsonb_path_query
------------------
2
(1 row)
Copyright©2019 NTT corp. All Rights Reserved.
{
“data1”: {
“a”: [1,2,3],
“b”: {
“c”: “cc”
}
},
“data2”: “d”
}
26
‘$.data1.a[*]’
jsonb_path_query
------------------
1
2
3
(3 rows)
Copyright©2019 NTT corp. All Rights Reserved.
{
“data1”: {
“a”: [1,2,3],
“b”: {
“c”: “cc”
}
},
“data2”: “d”
}
27
‘$.data1.a ? (@ % 2 == 0)’
jsonb_path_query
------------------
2
(1 row)
Copyright©2019 NTT corp. All Rights Reserved.
{
“data1”: {
“a”: [1,2,3],
“b”: {
“c”: “cc”
}
},
“data2”: “d”
}
28
‘$.data1.keyvalue()
jsonb_path_query
----------------------------------------------
{"id": 32, "key": "a", "value": [1, 2, 3]}
{"id": 32, "key": "b", "value": {"c": "cc"}}
(2 rows)
Copyright©2019 NTT corp. All Rights Reserved.
https://www.postgresql.org/docs/12/functions-json.html
29
JSON/PATHの演算子と関数
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
30
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
(例)
コインとサイコロを投げ、コインが裏で3の目が出る確率は?
コインを投げる事と、サイコロを投げる事は独立な事象と考えるこ
とができる。(コインの表裏によってサイコロの出る目の確率は変わらない)
P(A) = 1/2
P(B) = 1/6
P (A∩B) = P(A)P(B) = 1/2 * 1/6 = 1/12
31
行数見積もりの問題 - 事象の独立性 -
事象の独立性
P(A∩B) = P(A)P(B)
PostgreSQLでは、(問い合わせ結果の)行数を推定する際に、
列の値の独立性を仮定している
Copyright©2019 NTT corp. All Rights Reserved.
次のテーブルを考えてみる
• 住所テーブル
• 都道府県、市町村などが入っている
32
行数見積もりの問題
=# SELECT * FROM addresses;
prefecture | city | town | chome
------------+------+------+-----------------------------
東京都 | 港区 | 港南 |
東京都 | 港区 | 港南 |
東京都 | 港区 | 港南 | 品川インターシティA棟
東京都 | 港区 | 港南 | 品川インターシティA棟 1階
東京都 | 港区 | 港南 | 品川インターシティA棟 2階
東京都 | 港区 | 港南 | 品川インターシティA棟 3階
東京都 | 港区 | 港南 | 品川インターシティA棟 4階
東京都 | 港区 | 港南 | 品川インターシティA棟 5階
東京都 | 港区 | 港南 | 品川インターシティA棟 6階
東京都 | 港区 | 港南 | 品川インターシティA棟 7階
(10 rows)
Copyright©2019 NTT corp. All Rights Reserved. 33
行数見積もりの問題
QUERY PLAN
----------------------------------------------------------------------------------------
Seq Scan on addresses (cost=0.00..3476.01 rows=75 width=54)
(actual time=9.343..33.347 rows=1257 loops=1)
Filter: ((prefecture = '東京都'::text) AND (city = '千代田区'::text))
Rows Removed by Filter: 148144
Planning Time: 0.146 ms
Execution Time: 33.456 ms
(5 rows)(5 rows)
WHERE
prefecture = ‘東京都’
AND
city = ‘千代田区’
を考える。都道府県と市町村には相関がある。
(東京都の行には千代田区が出やすい)
見積値 75件に対し、
実際には1257件取得。
約16倍、行数見積が間違っている
Copyright©2019 NTT corp. All Rights Reserved.
PostgreSQLは各条件を独立の事象だとみなし見積を行っている
ため、結果行数を過小に見積もってしまった。
S(A)をAの選択率(Selectivity)とした時、
S(東京都) = 5.7%
S(千代田区) = 0.8%
S(東京都 ∩ 千代田区) = S(東京都)S(千代田区) = 5.7% * 0.8% = 0.05%
行数見積 = 全行数 * 選択率 = 149401 * 0.0005 ≒ 75
34
行数見積もりのズレ
P (A∩B) =
P(A)P(B)
Copyright©2019 NTT corp. All Rights Reserved.
• 相関関係のある複数列に跨った統計情報を作成できる
– 例) “都道府県”列と”市町村”列の値の組み合わせに対して統計情報を作
成する
• PostgreSQL 10で導入された機能
– Oracle Databaseには昔からある
• 複数条件に対する行数見積をより正確に行うことができる
• 作成できる統計情報
– ndistinct
– dependencies
– mcv (most common variables:最頻値)
35
CREATE STATISTICS(拡張統計情報)
Copyright©2019 NTT corp. All Rights Reserved. 36
拡張統計情報を使ってみる
=# CREATE STATISTICS stts ON prefecture, city FROM addresses;
CREATE STATISTICS
=# ANALYZE stts; --ANALYZE時に拡張統計情報が作成される
ANALYZE
=# EXPLAIN ANALYZE SELECT * FROM addresses
WHERE prefecture = '東京都‘ AND city = '千代田区';
QUERY PLAN
-------------------------------------------------------------------------------------
Seq Scan on addresses (cost=0.00..3476.01 rows=1290 width=54)
(actual time=10.958..37.468 rows=1257 loops=1)
Filter: ((prefecture = '東京都'::text) AND (city = '千代田区'::text))
Rows Removed by Filter: 148144
Planning Time: 0.493 ms
Execution Time: 37.584 ms
(5 rows)
=# SELECT m.* FROM pg_statistic_ext JOIN pg_statistic_ext_data on (oid = stxoid),
pg_mcv_list_items(stxdmcv) m WHERE m.values = ARRAY['東京都', '千代田区'];
index | values | nulls | frequency | base_frequency
-------+-------------------+-------+----------------------+-----------------------
2 | {東京都,千代田区} | {f,f} | 0.008633333333333333 | 0.0005001577777777778
(1 row)
正確に結果行数の
見積りができている
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
37
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• 独自のテーブル(Access Method)を定義、使用できるよう
なった
– インデックス(Index AM)は9.6から可能
• 夢が広がる機能
例えば
• OracleライクなUNDOベースのテーブル
• 列指向テーブル
• インメモリテーブル
• 他DBとの連携(RocksDB + PostgreSQLなど)
• 分散テーブル
38
Pluggable Storage Engine (Table AM)
Copyright©2019 NTT corp. All Rights Reserved.
https://www.pgcon.org/2019/schedule/attachments/559_pgcon-2019-transaction-logging.pdf
39
MySQLのStorage Engineとの違い
Copyright©2019 NTT corp. All Rights Reserved. 40
アーキテクチャ - これまで -
https://anarazel.de/talks/2018-10-25-pgconfeu-pluggable-storage/pluggable.pdf
Copyright©2019 NTT corp. All Rights Reserved. 41
アーキテクチャ - PG 12から -
https://anarazel.de/talks/2018-10-25-pgconfeu-pluggable-storage/pluggable.pdf
Copyright©2019 NTT corp. All Rights Reserved.
• 公式にサポートしているのはHeapのみ
• PostgreSQL 13では、なにか新しい種類のTable AMが入るか
もしれない
42
PostgreSQL 12ではAPIが切られただけ
Copyright©2019 NTT corp. All Rights Reserved.
• zheap (EnterpriseDB社)
– 行指向
– UNDOログ
– タプルヘッダが小さい
• ZedStore (Pivotal社)
– 列指向
– UNDOログ
– 圧縮
• In-memory table
43
どんなAccess Methodが今後入りそうか
Copyright©2019 NTT corp. All Rights Reserved.
• UNDOログを利用
– 古いタプルはすべてUNDO領域に退避
– Commitなら退避した古いタプルを消す、Rollbackならもとに戻す
• In-place update
• VACUUMがいらない
• タプルヘッダが従来のテーブルよりも小さい
– 25 bytes → 5 bytes
– MVCCに必要なデータはUNDOログにある
• ソースは公開されているので試してみるのもあり
– https://github.com/EnterpriseDB/zheap
44
zheap
Copyright©2019 NTT corp. All Rights Reserved.
目的は異なるが機能性は一部重複している
• 目的の違い
– FDWは外部データとの連携が目的(SQL/MEDの実装系)
– Table AMはPostgreSQLのストレージ層の切り出し
• 機能の違い
– FDWでは、実行計画の作成(外部サーバが担当する部分の切り出し等)、外
部サーバからのデータ取得を担当
• GetForeignPaths、GetForeignJoinPath, ExecForeignScanなど
– Table AMは、Executor⇔ストレージのI/Fのみ(今後変わる可能性あり)
• scan_getnextslot, index_fetch_begin, scan_bitmap_next_block, tuple_insert,
tuple_delete, scan_bitmapなど
– FDWではDDLに対応していない
45
Foreign Data Wrapperとの違い
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• Generated Columns(生成列)
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• 非互換
46
PostgreSQL 12の新機能
Copyright©2019 NTT corp. All Rights Reserved.
• WITH OIDSの廃止
• recovery.confの廃止
• recovery_target_XXXの重複指定禁止
47
影響が大きそうな非互換
Copyright©2019 NTT corp. All Rights Reserved.
対象者
CREATE TABLE ... WITH OIDSを使っている人
内容
• WITH OIDSが使えなくなった
• WITH OIDSがあるテーブルがあるとpg_upgradeが実行
できない
対処方法
• WITH OIDSを使わなくても良い設計を検討する
• ALTER TABLE ... SET WITHOUT OIDSでOIDSを取り除く
48
WITH OIDSの廃止
Copyright©2019 NTT corp. All Rights Reserved.
対象者
リカバリまたはレプリケーションをする人(= 全員)
内容
• recovery.confはなくなりpostgresql.confに統合された
• 代わりにrecovery.signalやstandby.signalファイルが必要
• recovery.confがあると起動しない
対処方法
• recovery.confに書いていたパラメータをpostgresql.confに書
くようにする
• リカバリ時はrecovery.signal、スタンバイ時はstandby.signal
を置くようにする
• recovery_target_XXXは設定ファイルに必ず一つになるよう
にすること
49
recovery.confの廃止
Copyright©2019 NTT corp. All Rights Reserved.
• SHOWコマンドでリカバリ関連の設定値が確認できる
• リカバリやスタンバイサーバの設定値をreloadで反映できる
– archive_cleanup_command
– promote_trigger_file
– recovery_end_command
– recovery_min_apply_delay
50
大きな非互換だけどその恩恵は大きい
Copyright©2019 NTT corp. All Rights Reserved.
• 新機能による恩恵とアップグレードのコストのトレードオフ
• これぞという機能があればアップグレードを検討
– 悩みをうまく解決してくれる機能があるかも
• もれなく運用ツールの修正コストが付いてくることに留意す
る
51
12へアップグレードするべき?
Copyright©2019 NTT corp. All Rights Reserved.
• テーブル・パーティショニングの改善
• CTE Inlining
• Vacuum改善
• SQL/JSON Path
• CREATE STATISTICS(拡張統計情報)
• Pluggable Storage Engine(Table AM)
• Generated Columns(生成列)
• 非互換
52
まとめ
Copyright©2019 NTT corp. All Rights Reserved.
Thank you