1. 改訂履歴

改訂日

変更内容

1.0

2023/03/31

新規作成

2. ライセンス

本作品はCC-BYライセンスによって許諾されています。 ライセンスの内容を知りたい方は こちら でご確認ください。 文書の内容、表記に関する誤り、ご要望、感想等につきましては、PGEConsのサイト を通じてお寄せいただきますようお願いいたします。

  • Eclipseは、Eclipse Foundation Incの米国、およびその他の国における商標もしくは登録商標です。

  • IBMおよびDb2は、世界の多くの国で登録されたInternational Business Machines Corporationの商標です。

  • Intel、インテルおよびXeonは、米国およびその他の国における Intel Corporation の商標です。

  • Javaは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。 文中の社名、商品名等は各社の商標または登録商標である場合があります。

  • Linux は、Linus Torvalds 氏の日本およびその他の国における登録商標または商標です。

  • Red HatおよびShadowman logoは、米国およびその他の国におけるRed Hat,Inc.の商標または登録商標です。

  • Microsoft、Windows Server、SQL Server、米国 Microsoft Corporationの米国及びその他の国における登録商標または商標です。

  • MySQLは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。 文中の社名、商品名等は各社の商標または登録商標である場合があります。

  • Oracleは、Oracle Corporation 及びその子会社、関連会社の米国及びその他の国における登録商標です。 文中の社名、商品名等は各社の商標または登録商標である場合があります。

  • PostgreSQLは、PostgreSQL Community Association of Canadaのカナダにおける登録商標およびその他の国における商標です。

  • Windows は米国 Microsoft Corporation の米国およびその他の国における登録商標です。

  • TPC, TPC Benchmark,TPC-C, TPC-E, tpmC, TPC-H, QphHは米国Transaction Processing Performance Councilの商標です

  • その他、本資料に記載されている社名及び商品名はそれぞれ各社が 商標または登録商標として使用している場合があります 。

3. 本資料概要

3.1. PostgreSQLエンタープライズコンソーシアムとWG3について

PostgreSQLエンタープライズコンソーシアム(略称 PGECons)は、PostgreSQL本体および各種ツールの情報収集と提供、整備などの活動を通じて、ミッションクリティカル性の高いエンタープライズ領域へのPostgreSQLの普及を推進することを目的として設立された団体です。
PGECons 技術部会ではPostgreSQLの普及に資する課題を活動テーマとし、3つのワーキンググループで具体的な活動を行っています。
  • WG1(新技術検証ワーキンググループ)

  • WG2(移行ワーキンググループ)

  • WG3(課題検討ワーキンググループ)

これら3つのワーキンググループのうち、WG1、WG3については 2015 年度まではそれぞれ、「性能ワーキンググループ」、「設計運用ワーキンググループ」という名称で活動してきました。2016年度は、従来の活動領域を広げる意図のもとでそれらを再定義し、上記のような名称に改めました。
これに伴い、WG3ではPostgreSQLの設計運用を中心としたさまざまな課題の解決のための調査検証を行い、PostgreSQLが広く活用されるように推進していくこととしました。

3.2. 本資料の概要と目的

本資料ではWG3の2022年度の活動として Amazon AuroraのPostgreSQL版(以下、Aurora PostgreSQL) における性能トラブルについて、調査・検討した結果をまとめました。
PGECons 既存成果物: 2018年度 WG3 活動報告書 性能トラブル調査編 の検証内容に対し、Aurora PostgreSQLを利用する際においても同様の対応を取れるかどうかを整理することを目的に、既存検証から一部項目を抽出し、検証を実施しました。
具体的には以下3つの内容についてまとめています。
  1. autovacuum のパラメータ検証

    autovacuum の処理性能を向上させるパラメータ設定値の検証を行います。
    以下のパラメータを調整し、2018年度検証と同じ傾向が Aurora PostgreSQL でも得られるか確認します。
    結果として、Aurora PostgreSQLはautovacuum の速度が2018年度検証のものと比べて実行時間が短く、テーブルサイズの肥大化が起こりにくいことを確認しました。
    autovacuum_vacuum_cost_delay
    autovacuum_vacuum_cost_limit
    
  2. 性能状態を把握するための監視

2018年度検証で整理されている性能に関連する情報 (以降、性能情報) に対し、Aurora PostgreSQLの機能 (Performance Insights等) で確認する方法があるか調査します。
Performance Insights等を用いることで、一部確認項目を代替することが出来ることを確認しています。
  1. ケーススタディ

3-1. ディスク性能の考慮漏れによる性能トラブル

2018年度検証の対応手順を基に、Aurora PostgreSQL において、ディスク性能の考慮漏れによる性能トラブルが発生するか、発生したトラブルがパラメータチューニングによって解決するかどうかを確認します。
Aurora PostgreSQL においては対象パラメータが最適化されており、本トラブルが起こりにくいことを確認しました。

3-2. 適切でない実行計画が選択されてしまうことによる性能トラブル

2018年度検証においてはヒント句の追加や統計情報の取得による実行計画の改善を行っていますが、新しい改善手法として、Aurora PostgreSQL の機能である Query Plan Management を用いた手順を整理します。
不適切な実行計画が選択されてしまう性能トラブルに対するチューニングの1つの手法として、QPMを用いることが出来ることを確認しています。
本資料で実施した検証項目と2018年度に実施した検証項目との対応は以下の表の通りです。

本検証項目

2018年度検証項目

4.autovacuumのパラメータ検証

4.6.1.autovacuumの処理時間とパラメータチューニング

5.性能状態を把握するための監視

5.性能状態を把握するための監視

6-1.ディスク性能の考慮漏れによる性能トラブル

6.2.ディスク性能の考慮漏れによる性能トラブル

6-2.適切ではない実行計画が選択されてしまうことによる性能トラブル

6.3.適切でない実行計画が選択されてしまうことによる性能トラブル

4. autovacuum のパラメータ検証

4.1. 検証環境

以下の環境で検証を実施しました。
Aurora PostgreSQLでパラメータが設定できないものについては、2018年度検証と異なる値が設定されております。
NOTE :
Aurora PostgreSQLのバージョンは検証当時の最新版である14.5を使用しましたが、
その後登場した14.6が2023年4月現在においては長期サポートの対象バージョンとなっており、利用が推奨されています。
表 4.1 autovacuum 検証の環境情報

項目

本検証パラメータ

2018年度検証

マシンスペック

db.r5.large (2vCPU, 16GB MEM)

2vCPU, 8GB MEM

Aurora(バージョン)

14.5.1

PostgreSQL

14.5

11.1

pgbench

PostgreSQL 14.1 付属

PostgreSQL 11.1 付属


表 4.2 autovacuum 検証の DB パラメータ

項目

本検証パラメータ

2018年度検証

max_connections

300

同左

shared_buffers

2GB

同左

effective_io_concurrency

256

200

max_wal_size

1GB

4GB

min_wal_size

0.5GB

2GB

checkpoint_completion_target

0.9

同左

random_page_cost

1.1

同左

autovacuum_vacuum_cost_limit

{200, 400, 600, 800, 1000}

同左

autovacuum_vacuum_cost_delay

{20, 15, 10, 5}

同左

autovacuum_vacuum_scale_factor

0.2

同左

4.2. 検証内容

削除や更新によって不要となった領域の再利用(VACUUM)を自動的に実行する autovacuum では、パラメータによって不要領域の回収速度を制御しています。
不要領域蓄積によるテーブルの肥大化を防ぐために autovacuum のパラメータチューニングが必要となります。
そこで、2018年度検証の"autovacuumによる不要領域の回収速度を各パラメータの設定値ごとに測定"と同条件で計測を実行することで、Aurora PostgreSQL における autovacuum のパラメータチューニングの効果を確認します。
autovacuum のチューニング対象となるパラメータの設定値を変更し、設定値ごとに autovacuum による不要領域の回収速度を測定します。
  1. 1000万件のデータが格納されたテーブルを作成

  2. 各パラメータ (autovacuum_vacuum_cost_limit, autovacuum_vacuum_cost_delay) に値を設定

  3. テーブルに UPDATE コマンドを実行し、テーブルの 25% (250万件) の不要領域を作成

  4. PostgreSQL のログメッセージより、autovacuum の処理時間を確認

NOTE :
Heap-only tuples (HOT) の効果を抑止するために更新対象の列にインデックスを作成します。

4.3. 検証結果

autovacuum パラメータの変更により、次のように autovacuum の処理時間が変化しました。
2018年度検証 と同じく、autovacuum_vacuum_cost_limit の値が大きくなるにつれ、 autovacuum の実行時間は小さくなる傾向となりました。
autovacuum_vacuum_cost_delay の値を増やせば autovacuum の実行時間は延び、autovacuum_vacuum_cost_limit の値を増やせば autovacuum の実行時間は短くなります。
_images/autovacuum_result.png

※ 下表は1秒間に autovacuum が処理できる平均行数、()内は autovacuum_vacuum_cost_limit=200、autovacuum_vacuum_cost_delay=20 を1とした場合との性能比率を示しています。

表 4.3 autovacuum_vacuum_cost_limit 変更による処理性能比較

設定値

200

400

600

800

1000

cost_delay=20

34261
(1.00)
61759
(1.80)
81081
(2.37)
101420
(2.96)
113139
(3.30)

cost_delay=15

44110
(1.29)
75980
(2.22)
100820
(2.94)
119218
(3.48)
133929
(3.91)

cost_delay=10

61200
(1.79)
101888
(2.97)
124008
(3.62)
148309
(4.33)
159473
(4.65)

cost_delay=5

101571
(2.96)
142884
(4.17)
170648
(4.98)
186706
(5.45)
193100
(5.64)
まず、パラメータの変更による autovacuum の処理時間の推移は、2018年度検証結果と Aurora PostgreSQL で同じ傾向が見られました。加えて、2018年度検証結果より Aurora PostgreSQL における autovacuum の方が大幅に性能が高い結果となりました。
2018年度検証 では、故意にテーブルサイズの肥大化させる目的で、以下の autovacuum パラメータを設定後、テーブルの 3.125% (31.25万行) を 1分ごとに更新しています。
Aurora PostgreSQL において同じ autovacuum パラメータで測定した場合は、autovacuum による不要領域の回収速度が不要領域の増加速度を上回り、不要領域の増加によるテーブル肥大化は起きませんでした。
autovacuum_vacuum_cost_limit=200
autovacuum_vacuum_cost_delay=20
_images/autovacuum_dead_tuples.png

4.4. 検証結果の考察

Aurora PostgreSQL の autovacuum の性能が高い結果となったのは、以下の要因が複合的に関連していると考えられます。

  • メジャーバージョンによる vacuum パフォーマンスの差異

  • HW 性能の不均一性

  • DB パラメータの差異

  • Aurora PostgreSQL のアーキテクチャーの優位性

ただし、Amazon Web Services Japan 社にも実施いただいた、オンプレミス想定のAmazon Relational Database Service(以下、RDS for PostgreSQL)とAurora PostgreSQL間のautovacuum性能差を確認する 追加検証結果 から、同一 HW、同一メジャーバージョンという前提において、Aurora PostgreSQL におけるアーキテクチャーの違いが autovacuum の性能差の大きな要因であると考えられます。 それに従い、今回の2018年度検証とAurora PostgreSQLのautovacuumの性能差の原因についても、アークテクチャの差が大きな要因となっていると考えられます。

4.4.1. 追加検証内容

以下の環境において、autovacuumの検証 と同じ手順で RDS for PostgreSQL 11, 12, 13, 14および Aurora PostgreSQL 11, 12, 13, 14の環境にて autovacuum の処理時間を計測しました。
下記表における同セル内の項目は、上から順にPostgreSQL11,12,13,14でのパラメータとなります。

NOTE :
マイナーバージョンは異なりますが、メジャーバージョンは同一です。

表 4.4 autovacuum 追加検証の環境情報

項目

RDS for PostgreSQL

Aurora PostgreSQL

マシンスペック

db.r5.large (2vCPU, 16GB MEM)

同左

Aurora

-
11.16.3
12.11.5
13.7.3
14.5.0

PostgreSQL

11.16
12.11
13.7
14.5

同左

autovacuum_vacuum_cost_limit

1000

同左

autovacuum_vacuum_cost_delay

5

同左

autovacuum_work_mem

-1 (default)
-1 (default)
496191kB
496191kB
-1 (default)
-1 (default)
496191kB (default)
496191kB (default)

maintenance_work_mem

260931kB (default)
260931kB (default)
254MB
254MB
254MB (default)
254MB (default)
254MB (default)
254MB (default)

4.4.2. 追加検証結果

各環境における autovacuum の処理時間は以下の結果となりました。

No.

engine

version

elapsed[s]

buffer usage

read rate[MB/s]

write rate[MB/s]

hits

misses

dirtied

R-1

RDS for PostgreSQL

11.16

77.70

667315

139654

529097

14.040

53.194

R-2

12.11

86.29

661441

140025

556627

12.677

50.392

R-3

13.7

41.63

630812

9673

110322

1.815

20.702

R-4

14.5

29.64

630922

9877

110700

2.603

29.170

A-1

Aurora PostgreSQL

11.16.3

13.86

807658

0

0

0.000

0.000

A-2

12.11.5

14.02

802280

0

0

0.000

0.000

A-3

13.7.3

11.63

641298

0

0

0.000

0.000

A-4

14.5.0

10.91

641608

0

0

0.000

0.000

  1. メジャーバージョンによる vacuum パフォーマンスの差異

バージョンの差異によるパフォーマンス変動の要素を排除するため、RDS for PostgreSQL と Aurora PostgreSQL において PostgreSQL の同一メジャーバージョンで測定を行いました。
RDS for PostgreSQL と Aurora PostgreSQL において、メジャーバージョンの差異による autovacuum の性能差には同じ傾向が見られます (R-1 ~ R-4 と A-1 ~ A-4) が、同一メジャーバージョンでは Aurora PostgreSQL の方が autovacuum の性能が高い傾向 (R-1 と A-1、R-2 と A-2、R-3 と A-3、R-4 と A-4) がありました。
そのため、PostgreSQL のバージョンによる性能差は考えられますが、それ以上に RDS for PostgreSQL と Aurora PostgreSQL のアーキテクチャの違いが大きく影響していると考えられます。
  1. HW 性能の不均一性

ストレージのアーキテクチャーが RDS for PostgreSQL と Aurora PostgreSQL で異なるものの、コンピュート性能を合わせるために基本的にオンプレミスの PostgreSQL と同等を想定した RDS for PostgreSQL と Aurora PostgreSQL において同一インスタンスクラス (db.r5.large) で autovacuum の処理時間を測定しました。
2018年度検証結果と比べ RDS for PostgreSQL の autovacuum の性能が高いため、2018年度検証環境と AWS での HW 性能が autovacuum の処理時間に影響していると考えられます。
  1. DB パラメータの差異

DB パラメータの autovacuum_work_mem および maintenance_work_mem を RDS for PostgreSQL と Aurora PostgreSQL において基本的に同一に設定し、autovacuum の処理時間を計測しました。
RDS for PostgreSQL 、Aurora PostgreSQL のバージョン12以下ではデフォルト値として変わりがなく、差異のあるバージョン13以上で RDS for PostgreSQL を Aurora に合わせましたが、特に両者の autovacuum 性能の傾向に差異はなく、パラメータの影響はない、もしくは小さいと考えられます。
  1. Aurora PostgreSQL のアーキテクチャーの優位性

Community 版の PostgreSQL(2018年度検証相当) の場合、vacuum を実施する際に vacuum 自身がページを変更するため、ページを dirty とマークし、最終的にストレージに書き戻す必要があります。
多くの dirty ページが発生する場合、vacuum のリングバッファが逼迫することが想定され、多くの dirty ページの書き戻しが発生していると考えられます。
Aurora PostgreSQL の場合、チェックポイントを含め PostgreSQL のページイメージをストレージに書き込む処理が不要なアーキテクチャーのため dirty ページの書き戻しが不要です。
autovacuum のログから書き込み量を比較すると RDS for PostgreSQL にはある程度の量の書き込みが確認できますが、Aurora PostgreSQL では書き込みが確認できません。そのため autovacuum の性能向上につながっていると考えられます。

NOTE :
また、Aurora PostgreSQL では visibility map を利用した vacuum の prefetch も Community 版の PostgreSQL より効率よく実施可能です。

5. 性能状態を把握するための監視

5.1. 検証環境(DBパラメータ)

以下のDBパラメータの設定を行い、検証を実施しました。
マシンスぺックやPostgreSQLバージョン等は、4.1に記載したものと同一です。

表 5.1 監視検証のDBパラメータ情報

項目

パラメータ

関連する検証項目

shared_preload_libraries

auto_explain,pg_stat_statements

No. 3

auto_explain.log_min_duration

0

No. 3

log_lock_waits

1

No. 26, 28

log_temp_files

0

No. 30

5.2. 検証内容

2018年度検証を基に、性能トラブル発生時にボトルネックの特定および分析を行う際に一助となる性能情報の確認方法を整理します。
2018年度検証ではDBに接続し、確認SQLを実行しておりましたが、以下のAWSやAurora PostgreSQLの機能を用いた確認方法があるかを調査しました。
NOTE :
Amazon CloudWatch メトリクスによる性能情報を取得することも可能ですが、Performance Insights と重複する項目が多く、本検証では性能情報の確認手段を可能な限りまとめるために、Performance Insights での確認方法に集約しました。

NOTE :
Performance Insights、拡張モニタリング、CloudWatch Logs の操作手順の詳細は本資料には記載しないため、各リンクの手順を確認してください。

NOTE :
Aurora PostgreSQL では、2018年度検証と同じ SQL を実行することも可能です。
2018年度検証と同等レベルの性能情報が確認できる場合は、Performance Insights など Aurora PostgreSQL 独自の機能を用いた確認方法を記載しています。

ただし、Performance Insights、拡張モニタリング、CloudWatch Logs へのログ出力には事前に以下の設定を行う必要があります。

  1. Performance Insights の有効化

DBクラスターを作成時、または作成後に、Performance Insights を有効にすることができます。
Performance Insights のデータ保持期間は、7日 (デフォルト)、1~24か月を指定することができます。
Performance Insights を有効化または無効化した場合でも再起動は必要ありません。

NOTE :
暗号化方式は DB クラスター作成時のみ設定できます。
  1. 拡張モニタリングの有効化

DB クラスターを作成時、または作成後に、拡張モニタリングを有効にすることができます。
モニタリング間隔は、1、5、10、15、30、60秒から選択でき、モニタリング用の IAM ロールを設定します。
拡張モニタリングを有効化または無効化した場合でも再起動は必要ありません。
  1. CloudWatch Logs へのログ出力

DBクラスターを作成時、または作成後に、CloudWatch Logs に PostgreSQL ログを定期的にエクスポートする設定を行います。
CloudWatch Logs へのログ出力を有効化または無効化した場合でも再起動は必要ありません。

5.3. 検証結果

まず、Aurora PostgreSQL においても2018年度検証と同じ SQL が実行可能であることを確認しました。その上で、Performance Insights等を用いることで、検証項目の一部メトリクスをDB接続することなく確認できることも確認しています。
特に、Performance Insights は、多くの性能情報を取得することができますが、データベースごとのメトリクス等の詳細情報ではなく、インスタンス全体のメトリクスや高負荷 SQL の確認に適しています。
そのため、基本的には Performance Insights で確認後、データベースごとに情報が知りたい場合等は SQL で確認します。
下表に各性能情報の確認方法をまとめます。
表 5.2 性能情報一覧

No

性能情報

2018年度検証の確認事項

Aurora PostgreSQLでの確認方法

Aurora PostgreSQLでの確認方法詳細

メトリクス

備考

1

トランザクション数

確認用SQL :
pg_stat_databaseビューによる
トランザクションコミット数と
ロールバック数の確認
確認用SQL
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

Performance Insightsではインスタンス全体の
トランザクション数は確認可能。
db.Transactions.xact_commit
db.Transactions.xact_rollback

2

SQLの統計情報

確認用SQL :
pg_stat_statmentによる
総実行時間と1回あたりの
実行時間が長いSQLの確認

Performance Insights

Performance Insightsの
トップSQLで確認

pg_stat_statementsのメトリクスは確認可能。

3

遅延SQL

ログ確認 :
auto_explainによる
指定時間より遅延したSQLの
実行計画の確認

CloudWatch Logs

shared_preload_librariesに
auto_explainを追加し、
auto_explain.log_min_durationで
閾値の処理時間を設定し、
CloudWatchのログから確認。
LOG、durationなどで検索。

4

実行中のロング
トランザクションの確認
確認用SQL :
pg_stat_activityビューによる
実行中の長時間
トランザクションSQLの確認
確認用SQL
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

・Performance Insightsでは以下のメトリクスが
 確認可能。
db.Transactions.active_transactions:
アクティブなトランザクション数
db.Transactions.blocked_transactions:
行ロックの取得を待機しているトランザクション数
db.Transactions.duration_commits:
1分間の合計トランザクション時間
db.Transactions.commit_latency:
コミットの平均所要時間
db.State.idle_in_transaction_count:
トランザクション実行状態で
アイドル状態のセッション数
db.State.idle_in_transaction_aborted_count:
トランザクション 中止状態で
アイドル状態のセッション数
db.State.idle_in_transaction_max_time:
トランザクション実行状態で
アイドル状態にあるセッションの最大時間
・Performance Insightsにおいて
 ある期間におけるAASやAAEの値から、
 平均して長時間実行されている
 クエリは確認可能。

5

VACUUMの実行状況

確認用SQL :
pg_stat_progress_vacuumビューによる
実行中の長時間VACUUMの確認
確認用SQL
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

・Performance Insightsにおいて
 ある期間におけるAASやAAEの値から、
 平均して長時間実行されている
 VACCUMに関連するクエリは確認可能。

6

CPU使用率

Linuxコマンド :
sarコマンドによる
CPU使用率の確認

Performance Insights

Performance Insightsの
カウンターメトリクスで確認
os.cpuUtilization.user
os.cpuUtilization.nice
os.cpuUtilization.system
os.cpuUtilization.wait
os.cpuUtilization.total

7

メモリ使用率

Linuxコマンド :
sarコマンドによる
メモリ使用率の確認

Performance Insights

Performance Insightsの
カウンターメトリクスで確認
os.memory.active
os.memory.inactive
os.memory.buffers
os.memory.cached
os.memory.free
os.memory.db.cache

8

スワップ発生率

Linuxコマンド :
sarコマンドによる
スワップ発生状況の確認

Performance Insights

Performance Insightsの
カウンターメトリクスで確認
os.swap.in
os.swap.out
os.swap.free
os.swap.cached

9

ディスクI/O

Linuxコマンド :
sarコマンドによる
ディスクI/O情報の確認

Performance Insights

Performance Insightsの
カウンターメトリクスで確認
os.diskIO.auroraStorage.diskQueueDepth
os.diskIO.auroraStorage.readIOsPS
os.diskIO.auroraStorage.readLatency
os.diskIO.auroraStorage.readThroughput
os.diskIO.auroraStorage.writeIOsPS
os.diskIO.auroraStorage.writeLatency
os.diskIO.auroraStorage.writeThroughput
2018年度検証とは確認方法が異なるが、
I/O負荷は確認可能。

10

ネットワーク使用状況

Linuxコマンド :
sarコマンドによる
送受信データ量の確認

Performance Insights

Performance Insightsの
カウンターメトリクスで確認
os.network.rx
os.network.tx

11

プロセスごとの
リソース使用率
Linuxコマンド :
topコマンドによる
プロセスのリソース状況の確認
拡張モニタリング
(Performance Insights
でも一部確認可能)

CloudWatch メトリクスで確認

processList.name
processList.cpuUsedPc
processList.memoryUsedPc
拡張モニタリングにおいて、プロセスごとの
disk I/Oは確認できない。
Performance InsightsではAAS/AAEが
確認できるため、リソースを
消費しているクエリは特定可能。

12

データベースサイズ

確認用SQL :
pg_databaseカタログによる
データベースサイズの
顕著な増加の有無の確認

確認用SQL

2018年度検証のSQLを実行

13

テーブルサイズ

確認用SQL :
pg_classカタログによる
インデックスサイズの
顕著な増加の有無の確認

確認用SQL

2018年度検証のSQLを実行

14

インデックスサイズ

確認用SQL :
pg_classカタログによる
テーブルサイズの
顕著な増加の有無の確認

確認用SQL

2018年度検証のSQLを実行

15

テーブルスキャン時の
読み込み行数
確認用SQL :
pg_stat_user_tablesビューによる
シーケンシャルスキャンの
実行回数と平均行数の確認

確認用SQL

2018年度検証のSQLを実行

16

インデックススキャンの
割合
確認用SQL :
pg_stat_user_tablesビューによる
インデックススキャンの割合の確認

確認用SQL

2018年度検証のSQLを実行

17

テーブル毎の
不要領域確認
確認用SQL :
pg_stat_user_tablesビューによる
テーブル毎の不要行の割合の確認

確認用SQL

2018年度検証のSQLを実行

18

テーブル断片化

確認用SQL :
pgstattuple_approx関数による
無効タプルと空き領域の割合の確認

確認用SQL

2018年度検証のSQLを実行

CREATE EXTENSION pgstattuple;
の実行が必要。

19

インデックス断片化

確認用SQL :
pgstatindex関数による
リーフページの断片化の割合の確認

確認用SQL

2018年度検証のSQLを実行

20

データベース毎の
キャッシュヒット率
確認用SQL :
pg_stat_databaseビューによる
データベース毎の
キャッシュヒット率の確認
確認用SQL :
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

Performance Insightsではインスタンス全体の
キャッシュヒット率は確認可能。
db.Cache.blks_hit

21

テーブル毎の
キャッシュヒット率
確認用SQL :
pg_statio_user_tablesビューによる
テーブル毎の
キャッシュヒット率の確認

確認用SQL

2018年度検証のSQLを実行

22

インデックス毎の
キャッシュヒット率
確認用SQL :
pg_statio_user_tablesビューによる
インデックス毎の
キャッシュヒット率の確認

確認用SQL

2018年度検証のSQLを実行

23

共有メモリ状況

確認用SQL :
pg_buffercacheビューによる
共有キャッシュ内の
バッファ数の確認

確認用SQL

2018年度検証のSQLを実行

CREATE EXTENSION pg_buffercache;
の実行が必要。

24

データベース毎の
同時接続数
確認用SQL :
pg_stat_activityビューによる
データベース毎の接続数の確認
確認用SQL :
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

Performance Insightsではインスタンス全体の
同時接続数は確認可能。
db.User.numbackends
db.User.total_auth_attempts

25

ロック待ち状態

確認用SQL :
pg_locksビューによる
ロック待ち回数の確認
確認用SQL :
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

Performance Insightsではインスタンス全体の
ロック待ちトランザクション数は確認可能。
db.Transactions.blocked_transactions

26

ロック待ちSQL

ログ確認 :
log_lock_waitsによる
ロック待ちSQLの確認
Performance Insights
(CloudWatch Logs
でも確認可能)
Performance Insightsの
トップSQLで確認。
CloudWatch Logsで確認する場合
log_lock_waitsを有効化する必要がある。

Performance Insightsでは、セッションの状態を
毎秒サンプリングしているため、
1秒未満の細かいロック状況を確認する場合は、
CloudWatchでのログ確認を検討してください。

27

デッドロック回数

確認用SQL :
pg_stat_databaseビューによる
デッドロック回数の確認
確認用SQL :
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

Performance Insightsではインスタンス全体の
デッドロック回数は確認可能。
db.Concurrency.deadlocks

28

デッドロックSQL

ログ確認 :
log_lock_waitsによる
デッドロックSQLの確認
Performance Insights
(CloudWatch Logs
でも確認可能)
Performance Insightsの
トップSQLで確認。
CloudWatch Logsで確認する場合
log_lock_waitsを有効化する必要がある。

29

SQLによる
ディスクソートの処理回数
(work_memの不足回数)
確認用SQL :
pg_stat_databaseビューによる
SQLによって書き出された
一時ファイルの個数とデータ量の確認
確認用SQL :
(Performance Insights
でも一部確認可能)

2018年度検証のSQLを実行

Performance Insightsではインスタンス全体の
一時ファイルへの書き込み回数と
データ量は確認可能。
db.Temp.temp_files
db.Temp.temp_bytes

30

ログメッセージの確認
(ディスクソート)
ログ確認 :
log_temp_filesによる
一時ファイルを作成したSQLの確認

CloudWatch Logs

log_temp_filesで閾値の
一時ファイルサイズを設定し、
CloudWatch Logsで確認

31

待機イベントの発生回数

確認用SQL :
pg_wait_sampling_profileビューによる
発生回数の多い待機イベントの確認

Performance Insights

Performance Insightsの
トップSQLで確認

Performance Insightsでは各待機イベントの
AAS/AAEを確認できるため、
各待機イベントの負荷状況が確認可能。

5.3.1. トランザクション数

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、データベース毎にトランザクションコミット数とロールバック数を確認できます。

  • Performance Insights による確認方法

Performance Insights から該当の DB インスタンスを選択後、以下のカウンターメトリクスを選択することで、データベース毎にトランザクションコミット数とロールバック数を確認できます。

db.Transactions.xact_commit
db.Transactions.xact_rollback
_images/transactions-xact.png

性能情報一覧に戻る

5.3.2. SQL の統計情報

  • Performance Insights による確認方法

Performance Insights から該当の DB インスタンスを選択後、負荷 (AAS) の高いクエリを表示するトップ SQL を確認することで、DB 負荷の高い SQL の統計情報を取得できます。

NOTE :
DB負荷指標のAASについては、 データベース負荷 を参照してください。

_images/stat-statment.png

性能情報一覧に戻る

5.3.3. 遅延 SQL

  • CloudWatch Logs による確認方法

パラメータグループの shared_preload_libraries パラメータに auto_explain を追加し、auto_explain.log_min_duration パラメータで閾値の処理時間を設定することにより、指定した時間よりも遅延した SQL の実行計画を自動的にログに出力します。
CloudWatch Logs から LOG、duration などの検索条件により、遅延 SQL の特定と実行計画の確認が可能となります。
_images/slow-query.png

性能情報一覧に戻る

5.3.4. 実行中のロングトランザクションの確認

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、実行中の SQL を確認できます。

  • Performance Insights による確認方法

SQL の統計情報 の確認手順と同様、トップ SQL を確認することで、任意の期間に実行された SQL を確認できます。

性能情報一覧に戻る

5.3.5. VACUUM の実行状況

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、実行中の VACUUM に関する情報を確認できます。

  • Performance Insights による確認方法

SQL の統計情報 の確認手順と同様、トップ SQL を確認することで、任意の期間に実行された VACUUM に関する情報を確認できます。

性能情報一覧に戻る

5.3.6. CPU 使用率

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、CPU 使用率を確認できます。

os.cpuUtilization.user
os.cpuUtilization.nice
os.cpuUtilization.system
os.cpuUtilization.wait
os.cpuUtilization.total

性能情報一覧に戻る

5.3.7. メモリ使用率

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、メモリ使用率を確認できます。

os.memory.active
os.memory.inactive
os.memory.buffers
os.memory.cached
os.memory.free
os.memory.db.cache

性能情報一覧に戻る

5.3.8. スワップ発生率

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、スワップ発生状況を確認できます。

os.swap.in
os.swap.out
os.swap.free
os.swap.cached

性能情報一覧に戻る

5.3.9. ディスクI/O

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、ディスク I/O 情報を確認できます。

os.diskIO.auroraStorage.diskQueueDepth
os.diskIO.auroraStorage.readIOsPS
os.diskIO.auroraStorage.readLatency
os.diskIO.auroraStorage.readThroughput
os.diskIO.auroraStorage.writeIOsPS
os.diskIO.auroraStorage.writeLatency
os.diskIO.auroraStorage.writeThroughput

性能情報一覧に戻る

5.3.10. ネットワーク使用状況

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、ネットワーク使用状況を確認できます。

os.network.rx
os.network.tx

性能情報一覧に戻る

5.3.11. プロセスごとのリソース使用率

  • 拡張モニタリングによる確認方法

DB インスタンスのモニタリングタブの OS プロセスリストから、プロセス一覧と負荷状況の確認が可能となります。
以下のメトリクスを確認することで、リソース利用の割合が高いプロセスを特定できます。
processList.name
processList.cpuUsedPc
processList.memoryUsedPc
_images/process.png
  • Performance Insights による確認方法

SQL の統計情報 の確認手順と同様、トップ SQL を確認することで、リソースを消費しているクエリを特定することができます。

性能情報一覧に戻る

5.3.12. データベースサイズ

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、データベース毎のサイズを確認できます。

性能情報一覧に戻る

5.3.13. テーブルサイズ

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、テーブル毎のサイズを確認できます。

性能情報一覧に戻る

5.3.14. インデックスサイズ

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、インデックス毎のサイズを確認できます。

性能情報一覧に戻る

5.3.15. テーブルスキャン時の読み込み行数

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、テーブルスキャン時の読み込み行数を確認できます。

性能情報一覧に戻る

5.3.16. インデックススキャンの割合

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、インデックススキャンの割合を確認できます。

性能情報一覧に戻る

5.3.17. テーブル毎の不要領域確認

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、テーブル毎の不要領域を確認できます。

性能情報一覧に戻る

5.3.18. テーブル断片化

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、テーブルの断片化情報を確認できます。

性能情報一覧に戻る

5.3.19. インデックス断片化

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、インデックスの断片化情報を確認できます。

性能情報一覧に戻る

5.3.20. データベース毎のキャッシュヒット率

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、データベース毎のキャッシュヒット率を確認できます。

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、DB インスタンス全体でのキャッシュヒット率を確認できます。

db.Cache.blks_hit

性能情報一覧に戻る

5.3.21. テーブル毎のキャッシュヒット率

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、テーブル毎のキャッシュヒット率を確認できます。

性能情報一覧に戻る

5.3.22. インデックス毎のキャッシュヒット率

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、インデックス毎のキャッシュヒット率を確認できます。

性能情報一覧に戻る

5.3.23. 共有メモリ状況

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、共有バッファの状態を確認できます。

性能情報一覧に戻る

5.3.24. データベース毎の同時接続数

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、データベース毎の同時接続数を確認できます。

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、DB インスタンス全体での同時接続数を確認できます。

db.User.numbackends
db.User.total_auth_attempts

性能情報一覧に戻る

5.3.25. ロック待ち状態

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、ロック待ち状態を確認できます。

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、DB インスタンス全体でのロック待ちトランザクション数を確認できます。

db.Transactions.blocked_transactions

性能情報一覧に戻る

5.3.26. ロック待ち SQL

  • Performance Insights による確認方法

SQL の統計情報 の確認手順と同様、トップSQLを確認することで、ロック待ち SQL を特定することができます。

  • CloudWatch Logsによる確認方法

log_lock_waitsを有効化した場合、遅延 SQL の確認手順と同様、ログからロック待ち SQL の確認ができます。

性能情報一覧に戻る

5.3.27. デッドロック回数

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、デッドロックの発生回数を確認できます。

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、DB インスタンス全体でのデッドロック回数を確認できます。

db.Concurrency.deadlocks

性能情報一覧に戻る

5.3.28. デッドロック SQL

  • Performance Insights による確認方法

SQL の統計情報 の確認手順と同様、トップ SQL を確認することで、デッドロックが発生した SQL を特定することができます。

  • CloudWatch Logs による確認方法

log_lock_waits を有効化した場合、遅延 SQL の確認手順と同様、ログからデッドロックが発生した SQL の確認ができます。

性能情報一覧に戻る

5.3.29. SQL によるディスクソートの処理回数 (work_mem の不足回数)

  • 確認用SQL による確認方法

確認用SQL と同じ SQL を実行することで、ディスクソートの発生情報を確認できます。

  • Performance Insights による確認方法

トランザクション数 の確認手順と同様、以下のカウンターメトリクスを選択することで、DB インスタンス全体の一時ファイルへの書き込み回数と書き込みデータ量を確認できます。

db.Temp.temp_files
db.Temp.temp_bytes

性能情報一覧に戻る

5.3.30. ログメッセージの確認 (ディスクソート)

  • CloudWatch Logs による確認方法

log_temp_files で閾値の一時ファイルサイズを設定した場合、遅延 SQL の確認手順と同様、ログから閾値以上のサイズの一時ファイルを作成した SQL の確認ができます。

性能情報一覧に戻る

5.3.31. 待機イベントの発生回数

  • Performance Insights による確認方法

SQL の統計情報 の確認手順と同様、トップ SQL を確認することで、待機イベント毎の負荷 (AAS) 状況と高負荷 SQL の確認ができます。

性能情報一覧に戻る

6. ケーススタディ

6.1. ディスク性能の考慮漏れによる性能トラブル

6.1.1. Aurora PostgreSQL ストレージの概要

Aurora PostgreSQL のストレージは、データベースのデータ量が増えるにつれて自動的に拡張され、Aurora PostgreSQL クラスターボリュームは、最大 128 TB のサイズまで増やすことができます。
そして、Aurora PostgreSQL のデータは SSD を使用する単一の仮想ボリュームであるクラスターボリュームに保存されます。
クラスターボリュームは、単一の AWS リージョンの 3つのアベイラビリティーゾーンに保持され、アベイラビリティーゾーン間で自動的にレプリケートされるため、ディスク障害に強い構造となっています。
Aurora PostgreSQL ストレージの詳細は Amazon Aurora ストレージと信頼性 を参照してください。

6.1.2. パラメータチューニング

2018年度検証では、ストレージタイプ(SSD / HDD)による性能影響とチューニング方法を検証しました。
具体的には、SSD を使用している環境において、実行計画のコスト算出に影響する seq_page_cost パラメータと random_page_cost パラメータが HDD を利用する想定の値に設定されているケースの検証を行いました。
HDD の利用想定でパラメータが設定されているため、ランダムアクセスの方がシーケンシャルアクセスより高速に結果を得られるにも関わらず、PostgreSQL がシーケンシャルアクセスを選択してしまい、理想より悪い性能となる可能性が高くなります。
2018年度検証では、以下のパラメータを制御することで利用しているディスクに適した値にすることにより、最適な実行計画が策定されるように改善しました。
seq_page_cost (シーケンシャルスキャンアクセスのコスト)
random_page_cost (ランダムアクセスのコスト)
一方、 Aurora PostgreSQL ストレージの概要 に記載しましたが、Aurora PostgreSQL ストレージには 必ずSSD が採用されるため、ストレージのタイプによるディスク性能を考慮する必要はありません。
加えて、実行計画のコスト算出に影響するseq_page_costパラメータ、random_page_costパラメータは、Aurora PostgreSQL アーキテクチャに合わせた適切な値で設計されています。
そのため、seq_page_cost 、random_page_cost のパラメータ値の変更自体はパラメータグループから可能ですが、基本的には変更の必要はなく、ディスク考慮漏れによる性能トラブルが起こる可能性は低いと考えられます。

6.2. 適切でない実行計画が選択されてしまうことによる性能トラブル

2018年度検証では、統計情報とデータベース内のデータの実態に剥離が生じ適切でない実行計画が選択されることで性能トラブルが発生した場合の解消法を紹介しました。
本来はハッシュジョインが採用されるべきところをマージジョインが選択されてしまったケースにおいて、enable_mergejoin パラメータの設定変更を行うことでマージジョインを避け、最適な実行計画が策定されるように改善しました。
また、時間の経過とともに統計情報が持つデータ件数と実際のデータ件数が乖離することによる最適な実行計画が選択されないケースにおいて、VACUUM ANALYZE を定期実行することで改善しました。
適切でない実行計画が選択されている場合のチューニング方法はいくつかありますが、Aurora PostgreSQL には、Query Plan Management (以下、QPM) という実行計画を固定化できる機能があります。
本ケーススタディの追加の解決方法として、QPM と従来手法 (2018年度検証) の違い、QPM を利用した性能トラブルの解消方法についてまとめます。

6.2.1. QPM 概要

QPM は、クエリの実行計画の変更方法と変更タイミングを制御する機能です。
実行計画の固定化などが可能となり、実行計画のリグレッションを回避することができます。
HINT句など実行計画の固定化手法はいくつか存在しますが、例えば、パッケージ製品を利用している等、アプリケーション (SQL文) の書き換えが難しい場合に QPM は有効です。
他にも、性能劣化が発生した際に緊急対応として直前の実行計画に戻したい場合等 QPM が有用なケースがあります。
詳細は Aurora PostgreSQL のクエリ計画管理の概要 を参照してください。

NOTE :
QPM は Aurora PostgreSQL の機能であり、 Community 版の PostgreSQL では使用できません。

6.2.2. QPM の特徴

従来のチューニング方法と比べた際に、QPM を用いたチューニング方法には以下の違いがあります。

特徴:
  • アプリケーション (SQL 文) の修正を伴わない。

  • 実行計画のバージョンを管理できる。 (アプリケーションが実行したクエリを全てキャプチャして管理することが可能)

  • 統計情報変更等により生成された効率の良い実行計画の自動検出、確認、の固定化ができる。

  • 実行計画の変更をすぐさま DB 全体に適用できる。

  • 性能改善に関する実行計画の変更のみ適用できる。 (実行計画のコストのみで判断)

  • 実行計画の取り込みと QPM の有効化は DB 再起動を伴わない。

注意点:
  • RDS for PostgreSQLでは使用できない。

  • 特定の SQL の実行計画が取得されない。

    • pg_class など、システムカタログを参照する SQL はキャプチャされない。

      • 内部で使用される多数のシステカタログで生成される実行計画がキャプチャされないための仕様である。

      • システムカタログの内部ビューも当てはまる。

  • ワークロードによっては、より大きな DB インスタンスクラスが必要になる場合がある。

  • パラメータによっては DB 再起動を伴う。

  • QPM のバージョン管理

    • QPMで利用する拡張機能のバージョンを、使用している Aurora PostgreSQL のバージョンの最新リリースに アップグレード することが推奨されている。

  • 長期間使用されていない、または有用ではない 実行計画の削除 が推奨されている。

  • QPM による実行計画の管理を行っている対象クエリの整理が必要となる。

    • アプリケーション (SQL 文) の修正を伴わない利点がある反面、QPMから管理対象の SQL は確認できるが、アプリケーション (SQL 文) 側からはQPMの対象か判断できない。

      • QPMによる実行計画の固定化を行っていることを開発/保守担当者が把握していない場合、アプリケーション (SQL 文) 側でHINT句による実行計画の固定化を実施しても、実行計画が更新されない問題が発生する可能性がある。

    • QPM の管理対象を整理し、実行計画の更新などの運用を行う必要がある。

6.2.3. QPM 実施手順

QPM の実施手順は以下になります。

  1. QPM の有効化

DBパラメータを設定し、QPMを有効化します。

  1. 実行計画の取得

DBパラメータを設定し、実行計画の自動取得、または、手動取得の設定を行います。

  1. 取得した実行計画の利用

DBパラメータを設定し、2. で取得した実行計画をオプティマイザが使用する設定を行います。

  1. 取得した実行計画の確認

取得した実行計画の履歴を確認します。

  1. 実行計画の管理

実行計画の追加、維持、および改善を行います。

QPM の各種詳細な実施手順は以下を参照してください。

6.2.3.1. QPM の有効化

Aurora PostgreSQL のクエリ計画管理をオンにする を参照してください。

6.2.3.2. 実行計画の取得

Aurora PostgreSQL 実行計画のキャプチャ を参照してください。

6.2.3.3. 取得した実行計画の利用

Aurora PostgreSQL 管理計画を使用する を参照してください。

6.2.3.4. 取得した実行計画の確認

dba_plans ビューで Aurora PostgreSQL クエリ計画を検証する を参照してください。

6.2.3.5. 実行計画の管理

Aurora PostgreSQL 実行計画の管理 を参照してください。

6.2.4. 実機確認

6.2.4.1. 検証環境

以下の環境で検証を実施しました。
マシンスぺックやPostgreSQLバージョン等は、4.1に記載したものと同一です。

表 6.1 QPM 検証の DB パラメータ

項目

パラメータ

rds.enable_plan_management

1

apg_plan_mgmt.capture_plan_baseline

manual

apg_plan_mgmt.use_plan_baselines

true

shared_preload_libraries

pg_stat_statements,pg_hint_plan

pg_hint_plan.debug_print

on

pg_hint_plan.enable_hint

1

pg_hint_plan.enable_hint_table

1

6.2.4.2. 検証内容

Amazon Aurora PostgreSQL でのクエリ計画管理のユースケース のユースケース#1, 2のシナリオで確認しました。

6.2.4.3. 検証結果

実行計画の固定化

  1. クエリ実行計画を取り込みます。  
    db01=> SET apg_plan_mgmt.capture_plan_baselines = manual;
    SET
    
  2. EXPLAINによりクエリ実行を実行し、実行計画を確認します。  
    db01=> explain (hashes true)
    db01-> SELECT Sum(delta),
    db01->            Sum(bbalance)
    db01-> FROM   pgbench_history h,
    db01->           pgbench_branches b
    db01-> WHERE  b.bid = h.bid
    db01->        AND b.bid IN ( 1, 2, 3 )
    db01->        AND mtime BETWEEN (SELECT Min(mtime)
    db01(>                           FROM   pgbench_history mn) AND (SELECT Max(mtime)
    db01(>                                                           FROM  pgbench_history mx);
                                         QUERY PLAN
    ------------------------------------------------------------------------------------
     Aggregate  (cost=164.17..164.18 rows=1 width=16)
       InitPlan 1 (returns $0)
         ->  Aggregate  (cost=53.00..53.01 rows=1 width=8)
               ->  Seq Scan on pgbench_history mn  (cost=0.00..49.00 rows=1600 width=8)
       InitPlan 2 (returns $1)
         ->  Aggregate  (cost=53.00..53.01 rows=1 width=8)
               ->  Seq Scan on pgbench_history mx  (cost=0.00..49.00 rows=1600 width=8)
       ->  Nested Loop  (cost=0.00..58.11 rows=8 width=8)
             Join Filter: (h.bid = b.bid)
             ->  Seq Scan on pgbench_branches b  (cost=0.00..1.01 rows=1 width=8)
                   Filter: (bid = ANY ('{1,2,3}'::integer[]))
             ->  Seq Scan on pgbench_history h  (cost=0.00..57.00 rows=8 width=8)
                   Filter: ((mtime >= $0) AND (mtime <= $1))
     SQL Hash: 1561242727, Plan Hash: 764058456
    
  3. 実行計画取り込み後にクエリ実行計画の取り込みをOFFにします。  
    db01=> SET apg_plan_mgmt.capture_plan_baselines = off;
    SET
    
  4. 取得した実行計画を表示します。  
    db01=> SELECT sql_hash,
    db01->           plan_hash,
    db01->           status,
    db01->           estimated_total_cost "cost",
    db01->           sql_text
    db01-> FROM apg_plan_mgmt.dba_plans;
      sql_hash  | plan_hash |  status  |   cost    |                                       sql_text
    ------------+-----------+----------+-----------+--------------------------------------------------------------------------------------
     1561242727 | 764058456 | Approved | 164.18375 | SELECT Sum(delta),                                                                  +
                |           |          |           |            Sum(bbalance)                                                            +
                |           |          |           | FROM   pgbench_history h,                                                           +
                |           |          |           |           pgbench_branches b                                                        +
                |           |          |           | WHERE  b.bid = h.bid                                                                +
                |           |          |           |        AND b.bid IN ( 1, 2, 3 )                                                     +
                |           |          |           |        AND mtime BETWEEN (SELECT Min(mtime)                                         +
                |           |          |           |                           FROM   pgbench_history mn) AND (SELECT Max(mtime)         +
                |           |          |           |                                                           FROM  pgbench_history mx);
    
  5. QPMで取り込んだ承認済み実行計画を使用する設定に変更します。  
    db01=> SET apg_plan_mgmt.use_plan_baselines = true;
    SET
    
  6. EXPLAINによりクエリ実行を実行し、QPMで固定化した実行計画が採用されていることを確認します。  
    db01=> explain (hashes true)
    db01-> SELECT Sum(delta),
    db01->            Sum(bbalance)
    db01-> FROM   pgbench_history h,
    db01->           pgbench_branches b
    db01-> WHERE  b.bid = h.bid
    db01->        AND b.bid IN ( 1, 2, 3 )
    db01->        AND mtime BETWEEN (SELECT Min(mtime)
    db01(>                           FROM   pgbench_history mn) AND (SELECT Max(mtime)
    db01(>                                                           FROM  pgbench_history mx);
                                         QUERY PLAN
    ------------------------------------------------------------------------------------
     Aggregate  (cost=164.17..164.18 rows=1 width=16)
       InitPlan 1 (returns $0)
         ->  Aggregate  (cost=53.00..53.01 rows=1 width=8)
               ->  Seq Scan on pgbench_history mn  (cost=0.00..49.00 rows=1600 width=8)
       InitPlan 2 (returns $1)
         ->  Aggregate  (cost=53.00..53.01 rows=1 width=8)
               ->  Seq Scan on pgbench_history mx  (cost=0.00..49.00 rows=1600 width=8)
       ->  Nested Loop  (cost=0.00..58.11 rows=8 width=8)
             Join Filter: (h.bid = b.bid)
             ->  Seq Scan on pgbench_branches b  (cost=0.00..1.01 rows=1 width=8)
                   Filter: (bid = ANY ('{1,2,3}'::integer[]))
             ->  Seq Scan on pgbench_history h  (cost=0.00..57.00 rows=8 width=8)
                   Filter: ((mtime >= $0) AND (mtime <= $1))
     SQL Hash: 1561242727, Plan Hash: 764058456
    
  7. 新しい計画を生成するために、pgbench_historyテーブルの「mtime」列に新しいインデックスを作成します。  
    db01=> create index pgbench_hist_mtime on pgbench_history(mtime);
    CREATE INDEX
    
  8. EXPLAINによりクエリ実行を実行し、QPM が新しい計画を検出した場合でも、承認した実行計画を維持していることを確認します。  
    db01=> explain (hashes true)
    db01-> SELECT Sum(delta),
    db01->            Sum(bbalance)
    db01-> FROM   pgbench_history h,
    db01->           pgbench_branches b
    db01-> WHERE  b.bid = h.bid
    db01->        AND b.bid IN ( 1, 2, 3 )
    db01->        AND mtime BETWEEN (SELECT Min(mtime)
    db01(>                           FROM   pgbench_history mn) AND (SELECT Max(mtime)
    db01(>                                                           FROM  pgbench_history mx);
                                         QUERY PLAN
    ------------------------------------------------------------------------------------
     Aggregate  (cost=164.17..164.18 rows=1 width=16)
       InitPlan 1 (returns $0)
         ->  Aggregate  (cost=53.00..53.01 rows=1 width=8)
               ->  Seq Scan on pgbench_history mn  (cost=0.00..49.00 rows=1600 width=8)
       InitPlan 2 (returns $1)
         ->  Aggregate  (cost=53.00..53.01 rows=1 width=8)
               ->  Seq Scan on pgbench_history mx  (cost=0.00..49.00 rows=1600 width=8)
       ->  Nested Loop  (cost=0.00..58.11 rows=8 width=8)
             Join Filter: (h.bid = b.bid)
             ->  Seq Scan on pgbench_branches b  (cost=0.00..1.01 rows=1 width=8)
                   Filter: (bid = ANY ('{1,2,3}'::integer[]))
             ->  Seq Scan on pgbench_history h  (cost=0.00..57.00 rows=8 width=8)
                   Filter: ((mtime >= $0) AND (mtime <= $1))
     Note: An Approved plan was used instead of the minimum cost plan.
     SQL Hash: 1561242727, Plan Hash: 764058456, Minimum Cost Plan Hash: -433405076
    
  9. 取得した実行計画を表示し、コストの低い実行計画が作成されているが、8. において承認された実行計画が採用されていることを確認します。  
    db01=> SELECT sql_hash,
    db01->           plan_hash,
    db01->           status,
    db01->           estimated_total_cost "cost",
    db01->           sql_text
    db01-> FROM apg_plan_mgmt.dba_plans;
      sql_hash  | plan_hash  |   status   |       cost       |                                       sql_text
    ------------+------------+------------+------------------+--------------------------------------------------------------------------------------
     1561242727 |  764058456 | Approved   |        164.18375 | SELECT Sum(delta),                                                                  +
                |            |            |                  |            Sum(bbalance)                                                            +
                |            |            |                  | FROM   pgbench_history h,                                                           +
                |            |            |                  |           pgbench_branches b                                                        +
                |            |            |                  | WHERE  b.bid = h.bid                                                                +
                |            |            |                  |        AND b.bid IN ( 1, 2, 3 )                                                     +
                |            |            |                  |        AND mtime BETWEEN (SELECT Min(mtime)                                         +
                |            |            |                  |                           FROM   pgbench_history mn) AND (SELECT Max(mtime)         +
                |            |            |                  |                                                           FROM  pgbench_history mx);
     1561242727 | -433405076 | Unapproved | 6.37206636451638 | SELECT Sum(delta),                                                                  +
                |            |            |                  |            Sum(bbalance)                                                            +
                |            |            |                  | FROM   pgbench_history h,                                                           +
                |            |            |                  |           pgbench_branches b                                                        +
                |            |            |                  | WHERE  b.bid = h.bid                                                                +
                |            |            |                  |        AND b.bid IN ( 1, 2, 3 )                                                     +
                |            |            |                  |        AND mtime BETWEEN (SELECT Min(mtime)                                         +
                |            |            |                  |                           FROM   pgbench_history mn) AND (SELECT Max(mtime)         +
                |            |            |                  |                                                           FROM  pgbench_history mx);
    
  10. コストの低い実行計画を承認  
    db01=> SELECT apg_plan_mgmt.set_plan_status (1561242727, '-433405076', 'Approved');
     set_plan_status
    -----------------
    0
    (1 row)
    
  11. 確認  
    db01=> SELECT sql_hash,
              plan_hash,
              status,
              estimated_total_cost "cost",
              sql_text
    FROM apg_plan_mgmt.dba_plans;
      sql_hash  | plan_hash  |  status  |   cost    |                                                                             sql_text
    ------------+------------+----------+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
     1561242727 |  764058456 | Approved | 164.18375 | SELECT Sum(delta),                                                                                                                                              +
                |            |          |           |            Sum(bbalance)                                                                                                                                        +
                |            |          |           | FROM   pgbench_history h,                                                                                                                                       +
                |            |          |           |           pgbench_branches b                                                                                                                                    +
                |            |          |           | WHERE  b.bid = h.bid                                                                                                                                            +
                |            |          |           |        AND b.bid IN ( 1, 2, 3 )                                                                                                                                 +
                |            |          |           |        AND mtime BETWEEN (SELECT Min(mtime)                                                                                                                     +
                |            |          |           |                           FROM   pgbench_history mn) AND (SELECT Max(mtime)                                                                                     +
                |            |          |           |                                                           FROM  pgbench_history mx);
     1561242727 | -433405076 | Approved |      6.37 | SELECT Sum(delta),                                                                                                                                              +
                |            |          |           |            Sum(bbalance)                                                                                                                                        +
                |            |          |           | FROM   pgbench_history h,                                                                                                                                       +
                |            |          |           |           pgbench_branches b                                                                                                                                    +
                |            |          |           | WHERE  b.bid = h.bid                                                                                                                                            +
                |            |          |           |        AND b.bid IN ( 1, 2, 3 )                                                                                                                                 +
                |            |          |           |        AND mtime BETWEEN (SELECT Min(mtime)                                                                                                                     +
                |            |          |           |                           FROM   pgbench_history mn) AND (SELECT Max(mtime)                                                                                     +
                |            |          |           |                                                           FROM  pgbench_history mx);
    (2 rows)
    
  12. クエリ実行  
    db01=> explain (hashes true)
    db01-> SELECT Sum(delta),
    db01->            Sum(bbalance)
    db01-> FROM   pgbench_history h,
    db01->           pgbench_branches b
    db01-> WHERE  b.bid = h.bid
    db01->        AND b.bid IN ( 1, 2, 3 )
    db01->        AND mtime BETWEEN (SELECT Min(mtime)
    db01(>                           FROM   pgbench_history mn) AND (SELECT Max(mtime)
    db01(>                                                           FROM  pgbench_history mx);
                                                                 QUERY PLAN
    -------------------------------------------------------------------------------------------------------------------------------------
     Aggregate  (cost=6.36..6.37 rows=1 width=16)
       InitPlan 2 (returns $1)
         ->  Result  (cost=0.30..0.31 rows=1 width=8)
               InitPlan 1 (returns $0)
                 ->  Limit  (cost=0.28..0.30 rows=1 width=8)
                       ->  Index Only Scan using pgbench_hist_mtime on pgbench_history mn  (cost=0.28..35.98 rows=1600 width=8)
                             Index Cond: (mtime IS NOT NULL)
       InitPlan 4 (returns $3)
         ->  Result  (cost=0.30..0.31 rows=1 width=8)
               InitPlan 3 (returns $2)
                 ->  Limit  (cost=0.28..0.30 rows=1 width=8)
                       ->  Index Only Scan Backward using pgbench_hist_mtime on pgbench_history mx  (cost=0.28..35.98 rows=1600 width=8)
                             Index Cond: (mtime IS NOT NULL)
       ->  Nested Loop  (cost=0.28..5.70 rows=8 width=8)
             Join Filter: (h.bid = b.bid)
             ->  Seq Scan on pgbench_branches b  (cost=0.00..1.01 rows=1 width=8)
                   Filter: (bid = ANY ('{1,2,3}'::integer[]))
             ->  Index Scan using pgbench_hist_mtime on pgbench_history h  (cost=0.28..4.59 rows=8 width=8)
                   Index Cond: ((mtime >= $1) AND (mtime <= $3))
     SQL Hash: 1561242727, Plan Hash: -433405076
    (20 rows)

pg_hint_plan を使用した QPM による実行計画の修正

  1. クエリ実行計画の取り込みをOFFにします。  
    db01=> SET apg_plan_mgmt.capture_plan_baselines = off;
    SET
    
  2. クエリを実行します。  
    db01=> EXPLAIN (hashes true)
    db01-> SELECT
    db01->    *
    db01-> FROM
    db01->    pgbench_branches b
    db01->    JOIN
    db01->       pgbench_accounts a
    db01->       ON b.bid = a.bid
    db01-> ORDER BY
    db01->    a.aid;
                                                        QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------
     Nested Loop  (cost=0.59..785331.41 rows=9964671 width=461)
       ->  Index Scan using pgbench_accounts_pkey on pgbench_accounts a  (cost=0.43..537663.60 rows=9964671 width=97)
       ->  Memoize  (cost=0.15..0.17 rows=1 width=364)
             Cache Key: a.bid
             Cache Mode: logical
             ->  Index Scan using pgbench_branches_pkey on pgbench_branches b  (cost=0.14..0.16 rows=1 width=364)
                   Index Cond: (bid = a.bid)
     SQL Hash: 356104612, Plan Hash: 2119829930
    
  3. 実行計画の取り込みむ設定に変更します。  
    db01=> SET apg_plan_mgmt.capture_plan_baselines = manual;
    SET
    
  4. ヒント句による実行計画の固定を行います。  
    db01=> /*+ HashJoin(a b) */  EXPLAIN (hashes true)
    db01-> SELECT
    db01->    *
    db01-> FROM
    db01->    pgbench_branches b
    db01->    JOIN
    db01->       pgbench_accounts a
    db01->       ON b.bid = a.bid
    db01-> ORDER BY
    db01->    a.aid;
    WARNING:  transaction left non-empty SPI stack
    HINT:  Check for missing "SPI_finish" calls.
                                                   QUERY PLAN
    ---------------------------------------------------------------------------------------------------------
     Gather Merge  (cost=2359260.50..3328115.55 rows=8303892 width=461)
       Workers Planned: 2
       ->  Sort  (cost=2358260.48..2368640.34 rows=4151946 width=461)
             Sort Key: a.aid
             ->  Hash Join  (cost=3.25..380752.47 rows=4151946 width=461)
                   Hash Cond: (a.bid = b.bid)
                   ->  Parallel Seq Scan on pgbench_accounts a  (cost=0.00..369388.46 rows=4151946 width=97)
                   ->  Hash  (cost=2.00..2.00 rows=100 width=364)
                         ->  Seq Scan on pgbench_branches b  (cost=0.00..2.00 rows=100 width=364)
     Note: This is not an Approved plan.  No usable Approved plan was found.
     SQL Hash: 356104612, Plan Hash: -58126597
    
  5. 取得した実行計画を表示します。  
    db01=> SELECT sql_hash,
           plan_hash,
           status,
           enabled,
           sql_text
    FROM   apg_plan_mgmt.dba_plans
     Where plan_hash='-58126597';
     sql_hash  | plan_hash |   status   | enabled |         sql_text
    -----------+-----------+------------+---------+---------------------------
     356104612 | -58126597 | Unapproved | t       | SELECT                   +
               |           |            |         |    *                     +
               |           |            |         | FROM                     +
               |           |            |         |    pgbench_branches b    +
               |           |            |         |    JOIN                  +
               |           |            |         |       pgbench_accounts a +
               |           |            |         |       ON b.bid = a.bid   +
               |           |            |         | ORDER BY                 +
               |           |            |         |    a.aid;
    
  6. 同じSQL HASHの別の実行計画を除外し、ヒント句を用いた実行計画を承認します。  
    db01=> SELECT apg_plan_mgmt.set_plan_status (sql_hash, plan_hash, 'Rejected') from apg_plan_mgmt.dba_plans where sql_hash = 356104612;
     set_plan_status
    -----------------
                   0
                   0
    db01=> SELECT apg_plan_mgmt.set_plan_status (356104612, '-58126597', 'Approved');
     set_plan_status
    -----------------
                   0
    
  7. 実行計画の取り込みをOFFにし、QPMで取り込んだ承認済み実行計画を使用する設定に変更します。  
    db01=> SET apg_plan_mgmt.capture_plan_baselines = off;
    SET
    db01=> SET apg_plan_mgmt.use_plan_baselines = true;
    SET
    
  8. ヒント句なしでクエリを実行しても、ヒント句で指定した実行計画が採用されていることを確認します。  
    db01=> EXPLAIN (hashes true)
    db01-> SELECT
    db01->    *
    db01-> FROM
    db01->    pgbench_branches b
    db01->    JOIN
    db01->       pgbench_accounts a
    db01->       ON b.bid = a.bid
    db01-> ORDER BY
    db01->    a.aid;
                                                   QUERY PLAN
    ---------------------------------------------------------------------------------------------------------
     Gather Merge  (cost=2359260.50..3328115.55 rows=8303892 width=461)
       Workers Planned: 2
       ->  Sort  (cost=2358260.48..2368640.34 rows=4151946 width=461)
             Sort Key: a.aid
             ->  Hash Join  (cost=3.25..380752.47 rows=4151946 width=461)
                   Hash Cond: (a.bid = b.bid)
                   ->  Parallel Seq Scan on pgbench_accounts a  (cost=0.00..369388.46 rows=4151946 width=97)
                   ->  Hash  (cost=2.00..2.00 rows=100 width=364)
                         ->  Seq Scan on pgbench_branches b  (cost=0.00..2.00 rows=100 width=364)
     Note: An Approved plan was used instead of the minimum cost plan.
     SQL Hash: 356104612, Plan Hash: -58126597, Minimum Cost Plan Hash: 2119829930
    
  9. もともと取り込まれていた実行計画が採用されず、ヒント句で指定した実行計画が承認されています。  
    db01=> SELECT sql_hash,
           plan_hash,
           status,
           enabled,
           sql_text
    FROM   apg_plan_mgmt.dba_plans
     Where sql_hash=356104612;
     sql_hash  | plan_hash  |  status  | enabled |         sql_text
    -----------+------------+----------+---------+---------------------------
     356104612 |  -58126597 | Approved | t       | SELECT                   +
               |            |          |         |    *                     +
               |            |          |         | FROM                     +
               |            |          |         |    pgbench_branches b    +
               |            |          |         |    JOIN                  +
               |            |          |         |       pgbench_accounts a +
               |            |          |         |       ON b.bid = a.bid   +
               |            |          |         | ORDER BY                 +
               |            |          |         |    a.aid;
     356104612 | 2119829930 | Rejected | t       | SELECT                   +
               |            |          |         |    *                     +
               |            |          |         | FROM                     +
               |            |          |         |    pgbench_branches b    +
               |            |          |         |    JOIN                  +
               |            |          |         |       pgbench_accounts a +
               |            |          |         |       ON b.bid = a.bid   +
               |            |          |         | ORDER BY                 +
               |            |          |         |    a.aid;

7. 著者

所属企業・団体名

部署名

氏名

1.0

日鉄ソリューションズ株式会社

アドバンストテクノロジー部

永井 光
秋山 暉佳