3
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 8

PG15/PG16:Differentiate MERGE queries with different structures

Last updated at Posted at 2022-12-07

はじめに

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

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

今回はPostgreSQL 15.0のリリース直前にcommitされた
pg_stat_statementsの改造内容を書いてみます。

概要

項目 内容
タイトル Differentiate MERGE queries with different structures
Topic Monitoring & Control
ステータス commited
Last modified 2022-09-28
概要 pg_stat_statementsでMERGE文のWHENのあとの複数種類の文を別々にカウントする

変更内容

これはPostgreSQL 15から追加されたMERGEコマンドをpg_stat_statementsで収集するときの問題を解決したものです。

MERGEコマンド

PostgreSQL 15からMERGEコマンドが使えるようになりました。
MERGEコマンドは条件によって、INSERT/UPDATE/DELETEの処理に分岐するコマンドです。

pg_stat_statementsモジュール

pg_stat_statementsは、サーバで実行されたすべてのSQL文のプラン生成時と実行時の統計情報を記録するモジュールです。
このモジュールはpg_stat_statementsビューと幾つかの関数を提供しているものです。

実運用時に性能問題が発生したときの、取っ掛かりとしてこの拡張機能は役立つので、多少の性能オーバヘッドがあるものの取り敢えず入れといて損はないものです。

動作検証

検証内容

postgresql.confに以下の設定を行ってPostgreSQLサーバを起動します。

shared_preload_libraries='pg_stat_statements'

検証要のデータベースにpg_stat_statementsを登録しておきます。

CREATE EXTENSION pg_stat_statements;

以下のような簡単なテーブルを作成します。

CREATE TABLE test (
  id  int primary key,
  data text
);

わかりやすくするために、pg_stat_statementsで収集した統計情報はリセットしておきます(これによりcallsが0になる)。

SELECT pg_stat_statements_reset();

以下の3つのSQLを実行します。

INSERT INTO test VALUES (1, 'ABC');

-- MERGE (insert)
MERGE INTO test AS t
USING (values (2, 'DEF')) AS i(id, data)
ON t.id = i.id
WHEN MATCHED THEN
    UPDATE SET data = i.data
;

-- MERGE (update)
MERGE INTO test AS t
USING (values (1, 'abc')) AS i(id, data)
ON t.id = i.id
WHEN MATCHED THEN
    DELETE;
;
  • 最初にidが1のレコードを挿入します。
  • 次のMERGE文ではマッチしたらUPDATEを行うのですが、実際にはマッチしないので、何もしません。
  • 次のMERGEではマッチした行をDELETEします。idが1の行がマッチするので、id=1の行はDELETEされます。

このクエリを実行すると、結果はこうなります。

TABLE test;
 id | data
----+------
(0 rows)

PostgreSQL 15以降の挙動

この状態で、pg_stat_statementsビューを参照します(今回はquery_id, query, callsのみ表示します)。

SELECT queryid, query, calls FROM pg_stat_statements ORDER BY query;
       queryid        |                 query                  | calls
----------------------+----------------------------------------+-------
  2265416722066910701 | INSERT INTO test VALUES ($1, $2)       |     1
 -1381799517176356930 | MERGE INTO test AS t                  +|     1
                      | USING (values ($1, $2)) AS i(id, data)+|
                      | ON t.id = i.id                        +|
                      | WHEN MATCHED THEN                     +|
                      |     DELETE                             |
 -6692072224192878392 | MERGE INTO test AS t                  +|     1
                      | USING (values ($1, $2)) AS i(id, data)+|
                      | ON t.id = i.id                        +|
                      | WHEN MATCHED THEN                     +|
                      |     UPDATE SET data = i.data           |
 -7024813306266399419 | SELECT pg_stat_statements_reset()      |     1
  7533749921200599032 | TABLE test                             |     1
(5 rows)

testテーブルに対するMERGE文は2回発行されてますが、WHEN句の内容が異なるものはそれぞれ別に1回ずつカウントされています。

PostgreSQL 15 beta版までの挙動

この修正なんですが、実はこの改修(2022-09-28にcommit)が入らなかったら、WHEN句が異なるMERGE文も同じものとしてカウントされていたようです。
以下は同じ検証をPostgreSQL 15 beta1で実施したものです(本当はbeta4やrc1でやりたかったけど、もうソースが入手できなかった・・・)。

SELECT queryid, query, calls FROM pg_stat_statements ORDER BY query;
       queryid        |                 query                  | calls
----------------------+----------------------------------------+-------
 -5907294925155083993 | INSERT INTO test VALUES ($1, $2)       |     1
  7315424997101376355 | MERGE INTO test AS t                  +|     2
                      | USING (values ($1, $2)) AS i(id, data)+|
                      | ON t.id = i.id                        +|
                      | WHEN MATCHED THEN                     +|
                      |     UPDATE SET data = i.data           |
 -2766515315050639636 | SELECT pg_stat_statements_reset()      |     1
 -2578912257006329778 | TABLE test                             |     1
(4 rows)

このようにMERGE文の種類は1つしか登録されず(MATCH DELETEのケースは登録されない)、かつ同じMERGEは文として2回実行されたとpg_stat_statementsで収集されてしまっていたようです。

なお、PostgreSQL 15.0のリリースノート改修項目としてはこの改造内容は明記されていないように思われます。既に消えてしまった、PostgreSQL 15 rc1版のリリースノートには記載されていたのかもしれませんが・・・。

おわりに

今回はPostgreSQL 15.0リリース時点では解決していた、pg_stat_statementsの問題が、PostgreSQL 15.0リリース直前のcommitで解決された、ということを書きました。

このcommitfest項目を確認したときに、PostgreSQL 15でもPostgreSQL 16でも挙動が変わらなくて何故だ・・・と悩みました。
今回のCommitfestにはこのようにPostgreSQL 15にも反映済みの項目もあることがわかったので、きちんとcommitされた日付も確認しないといけませんね。

3
0
0

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
3
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?