Aurora PostgreSQL 18.3がリリースされたのでPostgreSQL 18の新機能を試してみた

Aurora PostgreSQL 18.3がリリースされたのでPostgreSQL 18の新機能を試してみた

Amazon Aurora PostgreSQL-Compatible EditionがPostgreSQL 18(18.3)に対応しました。roaringbitmap拡張やB-treeスキップスキャン、uuidv7()、Virtual Generated Columns、OLD/NEW RETURNINGなど、PostgreSQL 18の主要な新機能をAurora上で実際に動作確認した結果を紹介します。Aurora固有の制約についても整理しました。
2026.06.12

はじめに

2026年6月11日、Amazon Aurora PostgreSQL-Compatible EditionがPostgreSQL 18(18.3)をサポートしました。

https://aws.amazon.com/jp/about-aws/whats-new/2026/06/amazon-aurora-postgresql-major-version-18/

コミュニティ版のPostgreSQL 18.0 GAは2025年9月25日でした。Auroraでの対応は約8.5か月後となります。AWSは2026年5月に公開したブログでAurora PostgreSQLのメジャーバージョン対応目標を「8か月以内」と説明しています。今回のリリースはおおむねその目標に近いタイムラインでの対応です。

https://aws.amazon.com/jp/blogs/database/knowing-when-new-open-source-database-engine-versions-release-on-amazon-aurora-and-amazon-rds/

なお、Auroraは18.0ではなく18.3で初版をリリースしています。コミュニティ側の3回分のマイナーリリースに含まれる累積的な修正を取り込んだ状態での提供です。

本記事では、Aurora PostgreSQL 18.3上で以下の新機能の動作確認を行いました。

  • roaringbitmap拡張(Aurora 18.3で新たに利用可能になった集合演算用拡張)
  • B-treeスキップスキャン
  • uuidv7() 組み込み関数
  • Virtual Generated Columns
  • OLD/NEW を使った RETURNING 構文

検証環境

項目
エンジン Aurora PostgreSQL-Compatible 18.3 (aurora_version 18.3.0)
リージョン ap-northeast-1
インスタンスクラス db.r8g.large(16 GiB RAM, Graviton4)
接続元 EC2 (AL2023 ARM64) → SSM Session Manager → psql
PostgreSQL 18.3 on aarch64-unknown-linux-gnu, compiled by aarch64-unknown-linux-gnu-gcc (GCC) 10.5.0, 64-bit

roaringbitmap 拡張

AWSのアナウンスでは「pg_roaringbitmap」として紹介されていますが、Aurora上で CREATE EXTENSION する際の拡張名は roaringbitmap です。

Roaring Bitmap は、多数の32bit整数IDの集合を効率的に圧縮格納するデータ構造です。積集合・和集合・差集合などの集合演算を効率的に実行できます。ユーザーセグメントの管理や、大量のID集合をデータベース内で効率的に表現したい場面で有用です。

動作確認

拡張を有効化し、ビットマップ型のカラムを持つテーブルを作成します。

CREATE EXTENSION roaringbitmap;

CREATE TABLE user_segments (
  segment_id int PRIMARY KEY,
  users roaringbitmap
);

INSERT INTO user_segments VALUES (1, rb_build(ARRAY[1,2,3,4,5,100,200]));
INSERT INTO user_segments VALUES (2, rb_build(ARRAY[3,4,5,6,7,200,300]));

積集合(AND)と和集合(OR)を試します。

-- 積集合
SELECT rb_to_array(rb_and(a.users, b.users))
FROM user_segments a, user_segments b
WHERE a.segment_id = 1 AND b.segment_id = 2;
 rb_to_array
-------------
 {3,4,5,200}
-- 和集合
SELECT rb_to_array(rb_or(a.users, b.users))
FROM user_segments a, user_segments b
WHERE a.segment_id = 1 AND b.segment_id = 2;
       rb_to_array
--------------------------
 {1,2,3,4,5,6,7,100,200,300}

カーディナリティ(要素数)も取得できます。

SELECT segment_id, rb_cardinality(users) FROM user_segments;
 segment_id | rb_cardinality
------------+----------------
          1 |              7
          2 |              7

拡張バージョンはv1.1でした。

SELECT extname, extversion FROM pg_extension WHERE extname = 'roaringbitmap';
    extname    | extversion
---------------+------------
 roaringbitmap | 1.1

B-tree スキップスキャン

PostgreSQL 18では、B-treeインデックスのスキップスキャンが導入されました。複合インデックスの先頭列に検索条件を指定しなくても、先頭列のdistinct値が少なければ後続列の条件でインデックスを活用できます。

動作確認

先頭列に条件を指定せず、後続列のみで検索します。

CREATE TABLE orders (
  status smallint,
  created_at timestamp,
  id serial PRIMARY KEY
);

INSERT INTO orders (status, created_at)
SELECT (random()*4+1)::smallint, now() - (random()*365)::int * interval '1 day'
FROM generate_series(1, 100000);

CREATE INDEX idx_orders_status_created ON orders (status, created_at);
ANALYZE orders;
EXPLAIN (ANALYZE, COSTS, BUFFERS)
SELECT * FROM orders WHERE created_at > now() - interval '7 days';

実行計画から該当部分を抜粋して示します(actual time等は省略)。

Index Scan using idx_orders_status_created on orders
  Index Cond: (created_at > (now() - '7 days'::interval))
  Index Searches: 6

先頭列に条件を指定していないにもかかわらず複合インデックスが選択され、Index Searches: 6 と複数回のインデックス探索が行われています。これは先頭列の値ごとに探索範囲をスキップしながらインデックスを走査する、スキップスキャンの動作と整合します。

status 列のdistinct値を確認すると5種類でした。

SELECT status, count(*) FROM orders GROUP BY status ORDER BY status;
 status | count
--------+-------
      1 | 12278
      2 | 25033
      3 | 25243
      4 | 25020
      5 | 12426

status 列のdistinct値は5ですが、実行計画上は Index Searches: 6 と観測されました。スキップスキャンの内部的な境界探索の挙動によるものと考えられます。本記事では検証環境で観測した結果としてそのまま記載します。

従来、先頭列に条件のない複合B-treeインデックスでは効率的に探索範囲を絞り込みにくく、シーケンシャルスキャンや別のインデックスの選択が一般的でした。

スキップスキャンにより、先頭列のdistinct値が少ないケースでは後続列条件でも複合インデックスを活用しやすくなります。

uuidv7() 組み込み関数

PostgreSQL 18では uuidv7() が組み込み関数として追加されました。

UUIDv7はタイムスタンプ情報を上位ビットに含むため、生成順と値の大小順序がおおむね一致します。B-treeインデックスとの相性がよいとされており、uuid_generate_v4() のようなランダムUUIDと比較してインデックスのページ分割や断片化を抑えやすいことが期待できます。

動作確認

10件連続で生成し、生成順と大小関係を確認しました。

SELECT n, v, v > lag(v) OVER (ORDER BY n) AS is_ordered
FROM (SELECT n, uuidv7() AS v FROM generate_series(1,10) AS g(n)) t
ORDER BY n;
 n  |                  v                   | is_ordered
----+--------------------------------------+------------
  1 | 019ebb09-b44c-7a03-a6cb-3ab47829fac5 |
  2 | 019ebb09-b44c-7a1b-a0c7-327cc7a70d4d | t
  3 | 019ebb09-b44c-7a1e-9f92-651835e8e0b6 | t
  4 | 019ebb09-b44c-7a1f-bff8-1a8ee8a1b769 | t
  5 | 019ebb09-b44c-7a21-85a4-34632ff35610 | t
  6 | 019ebb09-b44c-7a22-bd32-521bcf4799f8 | t
  7 | 019ebb09-b44c-7a24-9c77-392305d57fed | t
  8 | 019ebb09-b44c-7a25-820c-8e896d6e27dc | t
  9 | 019ebb09-b44c-7a27-9adc-e463421a57e2 | t
 10 | 019ebb09-b44c-7a28-8cb5-014d40f4c18f | t

1行目は lag() の比較対象がないためNULLです。2行目以降はすべて t となり、今回の検証では生成順とUUIDの大小関係が一致しました。

なお、UUIDv7の仕様上ミリ秒単位のタイムスタンプを含むため時系列順に並びやすい設計ですが、同一ミリ秒内の順序は実装依存であり、今回の検証結果をもって常にソート順が保証されるとは言えません。

Virtual Generated Columns

PostgreSQL 18では、Generated ColumnsのデフォルトがVIRTUALになりました。VIRTUAL生成列は値をディスクに保存せず、参照時に式を評価して計算します。

動作確認

CREATE TABLE products (
  id serial PRIMARY KEY,
  price numeric,
  tax_rate numeric DEFAULT 0.10,
  price_with_tax numeric GENERATED ALWAYS AS (price * (1 + tax_rate)) VIRTUAL
);

INSERT INTO products (price, tax_rate) VALUES (1000, 0.10), (2000, 0.08);
SELECT * FROM products;
 id | price | tax_rate | price_with_tax
----+-------+----------+----------------
  1 |  1000 |     0.10 |        1100.00
  2 |  2000 |     0.08 |        2160.00

price_with_tax が式 price * (1 + tax_rate) に基づいて算出されています。値を列として保存しないため、ストレージ使用量を抑えながら派生値を扱えます。一方で、VIRTUAL生成列を参照するクエリでは式の評価が発生するため、計算が重い場合はSTORED生成列との使い分けを検討する必要があります。

OLD/NEW RETURNING 構文

PostgreSQL 18では、UPDATEDELETERETURNING 句で oldnew の修飾子を使えるようになりました。更新前後の値を一度のクエリで取得できます。

動作確認

CREATE TABLE accounts (
  id serial PRIMARY KEY,
  balance numeric DEFAULT 0
);
INSERT INTO accounts (balance) VALUES (1000), (2000), (3000);

UPDATEで更新前後の値を同時に取得します。

UPDATE accounts SET balance = balance - 100
WHERE id = 1
RETURNING old.balance AS before, new.balance AS after;
 before | after
--------+-------
   1000 |   900

DELETEで削除前の値を取得します。

DELETE FROM accounts WHERE id = 3
RETURNING old.balance AS deleted_balance;
 deleted_balance
-----------------
            3000

従来は更新前の値を取得するためにサブクエリやCTEが必要でしたが、RETURNING old.* で直接参照できるようになりました。

Aurora 固有の制約と非互換性について

コミュニティPostgreSQL 18では非同期I/O(AIO)の仕組みが導入され、io_method などの新パラメータが追加されました。AWSドキュメントでは、Auroraは独自のI/O実装を使用するため、コミュニティPostgreSQL 18のAIO関連パラメータは利用対象外とされています。

検証環境で SHOW io_method; を実行すると、通常の接続ユーザーでは以下のエラーになりました。

postgres=> SHOW io_method;
ERROR:  must be Aurora superuser to examine "io_method"

https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Updates.html

また、PostgreSQL 18にはいくつかの互換性に影響する変更が含まれています。代表的なものを挙げます。

  • Generated ColumnsのデフォルトがVIRTUALに変更(前述)
  • MD5パスワード認証が非推奨(deprecated)として案内されるようになった(SCRAM-SHA-256への移行を推奨)
  • パーティション親テーブルに対する ANALYZE で子パーティションの統計情報も収集されるようになった

これ以外にも複数の変更があります。アップグレード前にはリリースノートで非互換性・制限事項を確認してください。

https://www.postgresql.org/docs/18/release-18.html

まとめ

本記事ではAurora PostgreSQL 18.3上で、PostgreSQL 18の主要な新機能の動作を確認しました。
検証した範囲ではいずれも想定どおりに動作しました。一方で、AIO関連パラメータのようにAuroraの独自実装により利用できない機能もある点には注意が必要です。

コミュニティGAから約8.5か月での対応はAWSが示す対応目標に近く、18.3を初版とすることでコミュニティ版PostgreSQL 18.3までの修正を含む形で提供されています。アップグレードの際は、非互換性の確認とあわせて新機能の活用余地を検討してみてください。

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事