4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PostgreSQL 16 全部ぬこAdvent Calendar 2022

Day 7

PG16:Tracking last scan time

Last updated at Posted at 2022-12-06

はじめに

にゃーん。趣味でポスグレをやっている者だ。

この記事はPostgreSQL 16 全部ぬこ Advent Calendar 2022 7日目の記事です。

今回はPostgreSQL 16で統計情報に追加された改造の内容を書いてみます。

概要

項目 内容
タイトル Tracking last scan time
Topic Monitoring & Control
ステータス commited
Last modified 2022-10-14
概要 統計情報ビューpg_stat_*_tableslast_seq_scan列とlast_idx_scan列を追加。
統計情報ビューpg_stat_*_indexeslast_idx_scan列を追加

変更内容

pg_stat_*_tables

PostgreSQL 16では、統計情報ビューpg_stat_*_tablesに以下の2つの列が追加されます。

列名 内容
last_seq_scan timestamp with time zone 該当のリレーションに対して最後にSeqScanによるアクセスが行われた時刻
last_idx_scan timestamp with time zone 該当のリレーションに対して最後にIndexScanによるアクセスが行われた時刻

pg_stat_*_indexes

PostgreSQL 16では、統計情報ビューpg_stat_*_indexesに以下の1つの列が追加されます。

列名 内容
last_idx_scan timestamp with time zone 該当のインデックスファイルに対して最後にアクセスが行われた時刻

どういうときに役に立つ?

この改善事項は、作成したインデックスがきちんと使われているかをチェックするのに役に立つと思われます。

例えばあるテーブルにインデックスを設定したけど、そのインデックスが実は使われないと、インデックス領域の無駄になるだけでなく、テーブルに更新があったときに同時に発生するインデックスの更新コストが無駄になります。

pg_stat_user_tableslast_seq_scanlast_index_scanの時刻を確認することで、最近そのテーブルに対してSeqScanがされた時刻や、そのテーブルに対して何らかのインデックスによるアクセスがされた時刻を確認できます。
例えば、あるテーブルに対してインデックスは作成したけど、そのインデックスを使う検索が全く行われなければ、last_index_scanのタイムスタンプは更新されず、last_seq_scanのタイムスタンプだけ更新される、という結果になります。

テーブルに対しては複数のインデックスが定義できるので、イネックスのうちどれかが使用されれば、pg_stat_user_tablesのタイムスタンプは更新されます。複数のインデックスのうち、どれかが使われない、という場合には、pg_stat_*_indexeslast_idx_scanを確認します。

実行例

ビルドバージョン

masterブランチのcommit 34fa0ddae5cf27dd93a5855b30083185d4bb5a5b--enable-debug --enable-cassertオプションつきでconfigureしてビルドした版を使っています。

masterブランチのcommit 8018ffbf5895ee16a1fd7117c4526b47ac42332eを``ビルドした版を使っています。(2022-12-07修正)

pgbench_accountsの例

pgbenchの-i -s 10オプションでpgbench_accountsテーブルを作成します。

$ ~/pgsql/master/bin/pgbench bench -i -s 10 -q
(省略)
generating data (client-side)...
1000000 of 1000000 tuples (100%) done (elapsed 2.27 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done in 3.55 s (drop tables 0.00 s, create tables 0.01 s, client-side generate 2.61 s, vacuum 0.15 s, primary keys 0.78 s).
$
$ psql bench -c "\d pgbench_accounts"
              Table "public.pgbench_accounts"
  Column  |     Type      | Collation | Nullable | Default
----------+---------------+-----------+----------+---------
 aid      | integer       |           | not null |
 bid      | integer       |           |          |
 abalance | integer       |           |          |
 filler   | character(84) |           |          |
Indexes:
    "pgbench_accounts_pkey" PRIMARY KEY, btree (aid)

わかりやすくするために、pg_stat_reset()を実行して、活動統計情報の内容をクリアし、その状態でpgbench_accountsテーブルのpg_stat_user_tablesの内容を確認します。

$ psql bench -c "SELECT pg_stat_reset()"
 pg_stat_reset
---------------

(1 row)

$ psql bench -P "null=(null)" -x -c "SELECT relname, seq_scan,last_seq_scan,idx_scan,last_idx_scan FROM pg_stat_user_tables WHERE relname = 'pgbench_accounts'"
-[ RECORD 1 ]-+-----------------
relname       | pgbench_accounts
seq_scan      | 0
last_seq_scan | (null)
idx_scan      | 0
last_idx_scan | (null)

$

pgbench_accountsaid列に対する=条件つきのクエリを実行し、実行後にpg_stat_user_tablesを再確認します。

$ psql bench -c "SELECT aid, bid, abalance FROM pgbench_accounts WHERE aid = 10000"
  aid  | bid | abalance
-------+-----+----------
 10000 |   1 |        0
(1 row)

$ psql bench -P "null=(null)" -x -c "SELECT relname, seq_scan,last_seq_scan,idx_scan,last_idx_scan FROM pg_stat_user_tables WHERE relname = 'pgbench_accounts'"
-[ RECORD 1 ]-+------------------------------
relname       | pgbench_accounts
seq_scan      | 0
last_seq_scan | (null)
idx_scan      | 1
last_idx_scan | 2022-12-07 10:01:39.024468+09

$

idx_scanがカウントアップされ、last_idx_scanが更新されているのがわかります。

今度は、WHERE句条件なしでabalance列のAVG()をとってみます。この検索ではSeqScanが実行されます。

$ psql bench -c "SELECT AVG(abalance) FROM pgbench_accounts"
            avg
----------------------------
 0.000000000000000000000000
(1 row)

$ psql bench -P "null=(null)" -x -c "SELECT relname, seq_scan,last_seq_scan,idx_scan,last_idx_scan FROM pg_stat_user_tables WHERE relname = 'pgbench_accounts'"
-[ RECORD 1 ]-+------------------------------
relname       | pgbench_accounts
seq_scan      | 3
last_seq_scan | 2022-12-07 10:02:50.276891+09
idx_scan      | 1
last_idx_scan | 2022-12-07 10:01:39.024468+09

$

seq_scanの数が0から3に増え、またlast_seq_scanのタイムスタンプが更新されているのがわかります。

なお、seq_scanが1ではなく3になっているのは、2つのWorkerを起動したパラレルクエリで実行されたからです。

$ psql bench -c "EXPLAIN SELECT AVG(abalance) FROM pgbench_accounts"
                                             QUERY PLAN
----------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=22602.55..22602.56 rows=1 width=32)
   ->  Gather  (cost=22602.33..22602.54 rows=2 width=32)
         Workers Planned: 2
         ->  Partial Aggregate  (cost=21602.33..21602.34 rows=1 width=32)
               ->  Parallel Seq Scan on pgbench_accounts  (cost=0.00..20560.67 rows=416667 width=4)
(5 rows)

$

パラレルクエリが実行された場合には、パラレルワーカーで実施されたスキャン方式の回数がカウントアップされるようですね。

おわりに

テーブルに対する最終シーケンシャルスキャンアクセス時刻・インデックスアクセス時刻や、インデックス毎の最終アクセス時刻をきちんと監視することで、より効率の良いインデックスのメンテナンスができるようになるかもしれません。
このあたりの監視・運用のノウハウも考えないといけませんね。

4
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?