PostgreSQL 14とその後:技術者Blog
PostgreSQLインサイド

Amit Kapila

FUJITSU Limited
Software Products Business Unit Data Management Division
Senior Director

はじめに

今回は、PostgreSQL 14の主な機能と、PostgreSQL 15以降の機能についてコミュニティーで議論されていることを話したいと思います。
バージョン9がリリースされてからは、PostgreSQLは大規模システムへの適用が増えています。製品が成熟期に達した今日でも、1年に1回程度の大きな機能追加や改善が行われています。
2021年12月9日(木曜日)に開催された当社のオンラインイベント「FUJITSU Software DevTech Days 2021」で、PostgreSQLの熱心なファンの方々に向けてお話しする機会がありました。
私はPostgreSQL 14に追加された機能と改良点について話し、これまでコミュニティーが議論してきたことに基づいてPostgreSQLの次の展開について議論しました。

目次

PostgreSQLの進化

  • 年に1回の継続的なバージョンアップ
  • 近年の大容量データ化への対応を強化

PostgreSQLの最初のバージョンはPostgres 6.0から登場しました。これは、1986年から開発が進められていたカリフォルニア大学バークレー校から継承したコードを使用して作成された、最初のオープンソースPostgreSQLリリースでした。
その後、ほぼ毎年メジャーバージョンがリリースされました。ここで、エンタープライズ向けに開発された、最近の特長をいくつか挙げてみます。例えば、バージョン9.0ではストリーミングレプリケーションが導入され、バージョン9.1では非同期レプリケーション、外部テーブル、およびログを取らないテーブルが導入されました。
同様に、次の数年間で、インデックスオンリースキャン、jsonデータ型、外部データラッパーへの更新、マテリアライズドビュー、およびjsonbデータ型を導入しました。その後、並列処理、宣言的パーティショニング、論理レプリケーションを導入し、大規模なCPUやマシン用にPostgreSQLを拡張するために、長年にわたるさまざまな性能強化を行いました。
バージョン12では、開発者や社外の利用者がテーブルにアクセスするための独自のストレージメソッドを作成できるテーブルアクセスメソッドを導入しました。私の同僚であるPankaj Kapoorは、「プラガブルストレージのテーブルへの展開!~テーブルアクセスメソッドインターフェイスへ取り組み~」という記事で、これについて書いています。
近年、エンタープライズ向けのさまざまな機能強化の概要を以下に示します。なお、以下の図では各バージョンの主な機能のみを記載しています。

図1:PostgreSQLのタイムライン
図1:PostgreSQLのタイムライン

PostgreSQL 14の主な機能

論理レプリケーションの改善

PostgreSQL 14で行われた論理レプリケーションの改善について説明します。

  • トランザクション処理中の論理レプリケーションをサポートしました。これにより、実行中の大規模なトランザクションの適用遅延を軽減させ、さらに改善できます。
  • プリペアドトランザクションのデコードも可能になりました。これは、マルチマスター・ソリューションの二相コミットの構築や、適用遅延の軽減に役立ちます。現在、PostgreSQL 14では、サブスクライバー側の作業はまだ行われていませんが、アウトオブコアのソリューションでは出力プラグインにこの機能を使用できます。この機能により、ユーザーはコンフリクトのないレプリケーションを構築できます。私の同僚であるAjin Cherianのブログ記事「二相コミットのロジカルデコーディング」で詳細を説明しています。
  • DDLを含むトランザクションのロジカルデコーディングの性能を改善しました。1,000個のパーティションを持つテーブルのトランケーションを含むトランザクションのデコードは、PostgreSQL 13以前では4分から5分かかっていたのに対し、1秒で終了します。
  • 論理レプリケーションにおいて、バイナリー形式のデータを転送できるようになりました。これは、やや堅牢性に劣るものの、一般的に高速です。
  • 論理レプリケーションのテーブル同期フェーズで、複数のトランザクションを実行できるようになりました。これには、次の利点があります。
    • 同期フェーズでエラーが発生した場合に、テーブル全体を再度コピーする必要はなくなりました。
    • CID(コマンド識別子)の制限を超えるリスクを回避できます。
    • 同期全体が完了するまでWALを保持する必要はなくなりました。この結果、初期同期に時間がかかる可能性がある非常に大規模なテーブルの論理レプリケーションが改善されました。
  • ALTER SUBSCRIPTION文にADD PUBLICATIONオプションとDROP PUBLICATIONオプションが追加され、パブリケーションの追加と削除が簡単になりました。
  • 「pg_stat_replication_slots」という、レプリケーションスロットの活動状況を報告する新しいビューが追加されました。これにより、ユーザーはディスクに書き出されたデータやストリームされた活動を監視できます。また、特定のスロットでデコードされたデータの総量も監視できます。

SQL機能

PostgreSQL 14では、他のデータベースからの移行に役立つ多くの機能が追加されています。

  • CREATE FUNCTION文とCREATE PROCEDURE文において、SQL言語をサポートするようになりました。その結果、関数本体はSQL標準に準拠し、他のデータベースからPostgreSQLへの移行に役立ちます。PostgreSQL固有の構文である「AS $$...$$」を使用する代わりに、以下の例のように引用符無しで本体を構成するSQL文を記述できます。

    CREATE PROCEDURE insert_val (value1 integer, value2 integer) LANGUAGE SQL
    BEGIN ATOMIC 
     INSERT INTO tbl1 VALUES (value1);
     INSERT INTO tbl1 VALUES (value2);
    END;
  • プロシージャにOUTパラメーターを指定できます。これにより、他のデータベースからの移行が簡単になります。
  • CREATE TRIGGER文にOR REPLACEを追加しました。これにより、既存のトリガーを条件付きで置き換えることができ、他のデータベースからの移行が簡単になります。当社の大墨 昂道がブログ記事「CREATE OR REPLACE TRIGGER」で詳細を説明しています。
  • ALTER TABLE構文で、DETACH PARTITION ... CONCURRENTLYがサポートされました。例を示します。

    ALTER TABLE [ IF EXISTS ] name
    DETACH PARTITION partition_name [ FINALIZE | CONCURRENTLY ]
    これにより、内部で2つのトランザクションが実行されるため、同時クエリをブロックすることなくパーティションをそのパーティション化されたテーブルから取り外すことができます。その2つのトランザクションが実行されるため、トランザクションブロック内では使用できません。2番目のトランザクションがキャンセルされた場合や、クラッシュが発生した場合は、ALTER TABLE ... DETACH PARTITION ... FINALIZEを指定していると、DETACH処理を完了します。
  • TRUNCATEは、postgres_fdwモジュールを使用した外部テーブルでも処理できるようになりました。
  • 添字が改善されました。拡張や組み込みデータ型で添字を実装できるようになりました。例えば、jsonbは次のように添字を使用できます。

    PostgreSQL 13以前

    SELECT jsonb_column->'key' FROM table;
    UPDATE table
    SET jsonb_column = jsonb_set(jsonb_column, '{"key"}', '"value"');

    PostgreSQL 14

    SELECT jsonb_column['key'] FROM table;
    UPDATE table
    SET jsonb_column['key'] = '"value"';
  • マルチ範囲データ型のサポートを追加しました。これらは範囲型に似ていますが、順序付きで、重複しない複数の範囲を指定できます。すべての既存の範囲型はマルチ範囲に対応します。以下に示すように、PostgreSQL 13以前では単一の日付範囲しか指定できませんでしたが、現在ではdatemultirange関数を使用して複数の日付範囲を指定できます。

    PostgreSQL 13以前

    SELECT daterange(CURRENT_DATE, CURRENT_DATE + 1);
           daterange
    -------------------------
     [2021-07-27,2021-07-28)

    PostgreSQL 14

    SELECT datemultirange( daterange(CURRENT_DATE    , CURRENT_DATE + 2),
                           daterange(CURRENT_DATE + 5, CURRENT_DATE + 8));
                       datemultirange
    ---------------------------------------------------
    {[2021-07-27,2021-07-29),[2021-08-01,2021-08-04)}
  • ECPGは、DECLARE STATEMENT構文をサポートするようになりました。これにより、ECPGのSQL識別子を特定の接続に紐づけできるようになりました。識別子が動的SQL文で使用される場合、これらのSQL文は紐づけられた接続を使用して実行されます。これは、DECLARE ... STATEMENTを使用します。以下に例を示します。

    EXEC SQL BEGIN DECLARE SECTION;
     char dbname[128];
     char *dym_sql = "SELECT current_database()";
    EXEC SQL END DECLARE SECTION;
    
    int main()
    { 
     EXEC SQL CONNECT TO postgres AS conn1; 
     EXEC SQL CONNECT TO testdb   AS conn2;
     EXEC SQL AT conn1 DECLARE stmt STATEMENT; 
     EXEC SQL PREPARE stmt FROM :dym_sql; 
     EXEC SQL EXECUTE stmt INTO :dbname;
     printf("%s\n", dbname); 
     EXEC SQL DISCONNECT ALL; 
     return 0;
    }

    上の例は、ユーザーが「SELECT current_database ()」のような単純な文を宣言してから、別のデータベースへの接続を定義する方法を示しています。その後、DECLARE STATEMENTを使用して、接続の1つを使用し、その接続で文を実行しています。これは、この機能を介して異なる接続で文を実行するアプリケーションに非常に便利です。

データ破壊への対応

PostgreSQLは現在、データベースが破損しているかどうかをユーザーが確認するためのいくつかのツールを提供しています。また、データベースの破損を可能な限り修正するための小さなツールも提供しています。

  • amcheckモジュールにヒープページをチェックする機能が追加されました。これまでは、B-treeインデックスページのみをチェックしていました。
  • コマンドラインユーティリティーにpg_amcheckを追加しました。これは、多くのリレーションでcontrib / amcheck操作を簡単に実行できるようにするためです。どのリレーションをチェックするか、どのチェックを実行するかを選択するための様々ななオプションが用意されており、必要に応じてチェックを並列に実行できます。
  • 行の可視性情報を変更できるpg_surgeryモジュールを追加しました。これはデータベースの破損を修正する場合に便利です。一方で、使用方法を誤ると、以前は破損していなかったデータベースを簡単に破損させたり、すでに破損しているデータベースをさらに破損させたり、データを破壊したりする可能性があります。強調したいのは、このツールは慎重に使用し、自分が行っていることを理解しているユーザーだけが使用する必要があるということです。

インデックス処理

  • データが事前にソートされ、GiSTインデックスを構築できるようになりました。事前ソートは自動的に行われ、インデックス作成の高速化とインデックスの小型化を可能にします。現在は、pointデータ型に対してのみサポートされています。
  • BRINインデックスで、範囲ごとに複数のmin / max値を記録できるようになりました。これは、各ページ範囲に値のグループがある場合に便利です。これにより、異常値をより効率的に処理できます。各ページ範囲で保持する値の数を、1つの値または間隔の境界として指定できます。

    CREATE TABLE table_name (a int);
    CREATE INDEX ON table_name USING brin (a int4_minmax_multi_ops(values_per_range=16));
  • BRINインデックスにbloomフィルターを使用できるようになりました。これにより、BRINインデックスを、ヒープ内で物理的にローカライズされていないデータに対して効果的に使用できます。
  • SP-GiSTインデックスに、INCLUDE句に指定された列を含めることができるようになりました。これにより、SP-GISTインデックスのインデックスオンリースキャンが可能になります。
  • REINDEXはパーティショニングされたリレーションのすべての子テーブルまたはインデックスを処理できるようになりました。
  • REINDEXが新しいインデックスのテーブル空間を変更できるようになりました。これを行うには、TABLESPACE句を指定します。これを制御するため、reindexdbに--tablespaceオプションも追加されました。

拡張統計情報

拡張統計情報が強化されました。これは、式が使用される様々な種類のクエリに対して、より良い統計情報を使用するのに役立ちます。同様に、そのようなクエリのためのより良い問い合わせ計画を生成するのにさらに役立ちます。

  • 拡張統計情報に式が使用できるようになりました。簡単な例を次に示します。

    CREATE TABLE table_name (a int);
    CREATE STATISTICS statistics_name ON mod(a,10), mod(a,20) FROM table_name;
    ANALYZE table_name;

    収集された統計情報は、例えば、WHERE句またはGROUP BY句にこれらの式を含むクエリを見積もる場合に役立ちます。

    SELECT * FROM table_name WHERE mod(a,10) = 0 AND mod(a,20) = 0;
    SELECT 1 FROM table_name GROUP BY mod(a,10), mod(a,20);

    この機能により、クエリに式が使用されている場合、より良い問い合わせ計画が作成できます。

  • OR句の推定に拡張統計を使用できる箇所が増えました。

バキューム処理

以前のリリースと同様に、PostgreSQLのバキューム処理も改善されており、このリリースにも様々な機能が追加されています。

  • 削除可能なインデックス項目の数が少ない場合に、インデックスのバキューム処理をスキップできます。これにより、バキューム処理時間が短縮されます。
  • テーブルがトランザクションIDやマルチトランザクションIDの周回に近い場合、バキューム操作をより積極的に行うようにしました。これは、vacuum_failsafe_ageおよびvacuum_multixact_failsafe_ageパラメーターによって制御されます。このメカニズムは、ほとんどの場合、自動バキュームが開始されてから長い時間が経過した後に、周回を防ぐために自動バキューム内で起動することが期待されます。
  • 既存の統計情報を可能な限り利用することにより、多くのリレーションを持つデータベースのバキューム処理を高速化しました。例えば、20000個のテーブルと10個のautovacuumワーカーが動作している場合、性能が3倍以上向上したことがベンチマーク結果で示されました。
  • バキュームが新たに削除されたB-treeページを積極的に空き領域マップに追加することで、再利用できるようになりました。これまでのバキュームでは、削除された既存のページだけを空き領域マップに追加していました。この改善により、B-treeインデックスに新しいページを割り当てる必要性が減り、インデックスのサイズが最適化されます。
  • バキュームは、未使用の末尾のヒープ行ポインターが使用している領域を、再利用できるようになりました。これにより、特定のワークロード、特に同じテーブルに対する連続した範囲のDELETEや一括INSERTを伴うワークロードでの行ポインターの肥大化を回避できます。
  • バキュームは、CREATE INDEX CONCURRENTLYおよびREINDEX CONCURRENTLY操作中において、無効行の削除をより積極的に行えるようになりました。

PostgreSQL 14の性能改善

このリリースには、性能を向上させるいくつかの変更が含まれています。それらを見てみましょう。

  • 多数のCPUを搭載し、セッション数の多いシステムでMVCC可視性スナップショットを計算する速度が向上しました。これにより、アイドル状態のセッションが多い場合の性能も向上します。読み取り専用のクエリで接続数が非常に多い場合には、約2倍の向上となります。
  • 影響を受けるパーティションが少ない場合に、パーティショニングテーブルでの更新 / 削除の性能が向上しました。これにより、パーティショニングテーブルの更新 / 削除で、実行時のパーティションプルーニングを使用することもできます。継承されたUPDATE / DELETEでは、対象となるリレーションごとに個別のサブプランを生成するのではなく、SELECTのプランと全く同じ単一のサブプランが生成されるようになり、その上位にModifyTable(プランノード)が追加されます。
  • 複数の外部テーブルを参照するクエリで、外部テーブルのスキャンを並行して実行できるようになりました。現在、同時に実行できるノードタイプは、Append直下の子ノードであるForeignScanだけです。このような複数のForeignScanが異なるリモートサーバー上のデータにアクセスする場合、ForeignScanを同時に実行し、同時に実行されるリモート操作をオーバーラップさせるため、特に操作に時間がかかる場合に性能が向上します。postgres_fdwはasync_capableが設定されていれば、このタイプのスキャンをサポートします。
  • TOASTデータにLZ4圧縮を使用できるようになりました。これは列レベルで設定するか、サーバー設定default_toast_compressionを使用してデフォルトとして設定することができます。この機能をサポートするには、--with-lz4を指定してPostgreSQLサーバーをコンパイルする必要があります。デフォルトはPGLZのままです。LZ4はCPU使用率が低く、PGLZよりも優れた圧縮を実現します。テストの結果、LZ4を使用すると速度が2倍以上向上し、サイズが若干大きくなることがわかりました。いずれかの方法を使用する前に、本番データでテストすることをお勧めします。唐 海英は、このオプションの使用方法を説明し、その性能を他の方法と比較しています。彼女のブログ記事「LZ4 TOAST圧縮」をお読みください。
  • B-treeインデックスへの機能追加で、ページ分割を防ぐために期限切れのインデックスエントリーを削除できるようになりました。これは、インデックス付きの列が頻繁に更新されるテーブルのインデックスの肥大化を抑えるのに特に役立ちます。このメカニズムは、連続するUPDATEからのバージョンの変更によって発生したと思われる重複がページに存在する場合、その重複を削除しようとします。
  • libpqにパイプラインモードが実装されました。これにより、複数のクエリを送信し、特定の同期メッセージが送信されたときにのみ完了を待つことができます。クライアントアプリケーションの複雑さが増し、クライアント / サーバーのデッドロックを防ぐために特別な注意が必要になりますが、パイプラインモードは、状態を長く保持することによるメモリー使用量の増加と引き換えに、性能を大幅に向上させることができます。パイプラインモードは、サーバーが遠方にある場合、つまり、ネットワークのレイテンシ(ping time)が大きい場合や、多数の小さな操作が高速で連続して実行されている場合に最も有効です。
  • ネステッドループ結合の内側からの結果をキャッシュする、エグゼキュータメソッドが追加されました。これは、内側でチェックされる行の割合が少ない場合に有用で、GUCパラメーター enable_memoizeによって制御されます。検索される個別の値が少なく、各値の検索回数が多い場合、パラメーター化されたネステッドループを結果のキャッシュと一緒に利用する利点は大きくなります。
  • FDW APIとpostgres_fdwが拡張され、外部テーブルへの一括挿入が可能になりました。FDWが一括処理をサポートし、一括処理が要求された場合は、行を累積し、一括して挿入します。それ以外の場合は、行単位の挿入を使用します。外部サーバーへの各ラウンドトリップのレイテンシが高いため、通常は、個々の行を挿入するよりも一括処理の方がはるかに効率的です。
  • expr IN (const-1、const-2, etc.)句を持つクエリの性能が向上しました。これは、現在の線形探索をハッシュテーブル検索に置き換えることによって実現されます。
  • 巨大な共有バッファーを持つクラスタでのリカバリー時に、小さなテーブルに対するトランケート、削除、またはCREATE TABLE操作のアボートの性能が向上しました。これにより、複数の小さなテーブル(1,000個のリレーションでテスト)がトランケートされ、サーバーが大きな値の共有バッファー(100GB以上)で構成されている場合に、多くのケースで性能が100倍以上向上します。
  • 大規模な更新のリカバリー、スタンバイ適用およびバキュームの性能が向上しました。性能の向上は、大規模な更新の後に使用する必要がある、ページを圧縮するアルゴリズムの最適化によってもたらされます。
  • 並列シーケンシャルスキャンのI/O性能が向上しました。これは、パラレルワーカーにグループ単位でブロックを割り当てることで実現しました。

PostgreSQL 14で追加または拡張された機能の完全なリストはPostgreSQLの公式サイト内「Release Notes」で確認できます。

PostgreSQL 15以降の展開

最後に、コミュニティーで議論されていて、PostgreSQL 15以降に組み込まれる可能性がある機能を挙げたいと思います。
なお、以下の機能は主観的なものであり、将来のリリースに含まれる保証はないことを強調しておきます。以下のリストはPostgreSQLコミュニティーの議論に関する私の個人的な見解に基づくものであり、私もコミュニティーもこれらの機能が実現されるかどうかを保証することはできません。

  • 論理レプリケーションのさまざまな改善
    • サブスクライバー側での二相コミットのサポート
    • スキーマのパブリケーション
    • コンフリクトの解決を可能にするオプション/ツール
    • シーケンスのレプリケーション
    • データのシャーディングを容易にする行レベルのフィルター
    • 列レベルのフィルタリング
    • 空のトランザクションを送信しないことによるネットワーク帯域幅の改善
    • スタンバイ側からの論理レプリケーションの有効化
  • バックアップ技術におけるサーバー側の圧縮
  • 自動スイッチオーバー / フェイルオーバーの改善
  • ハッシュインデックスの改善
    • 一意インデックスを許可
    • 複数列のインデックスを許可
  • 共有メモリー統計情報コレクター
    • UDPプロトコルを介する通信が不要になることによる信頼性の向上
    • readとwriteの回数が減ることによる性能向上
  • 並列書き込み
    • 並列挿入
    • 並列 Copy From...
    • パラレルクエリの改善
  • 非同期I/O
    データのプリフェッチが可能となることによる、システムの速度向上
  • ダイレクトI/O
    OSキャッシュがバイパスされることによる性能向上(場合による)
  • FDWによる二相コミット
    PostgreSQLベースのシャーディングソリューションの進化を促進
  • パフォーマンスデータストラクチャーを用いたバキューム技術の向上
  • パーティショニング技術の向上
  • グローバル一時テーブル
    一時テーブルの管理が改善されることによる、移行の容易化
  • マテリアライズドビューのインクリメンタルメンテナンス

まとめ

PostgreSQLの機能開発では、PostgreSQLの性能を向上させ、マルチマスターや分散ワークロードにさらに適したものにし、大規模な読み取り / 書き込みワークロードに対してより堅牢にし、移行を容易にすることに常に重点を置いていると言えます。
PostgreSQLは常に人気を博しており、データを管理するための最も一般的でデフォルトの選択肢となっています。これはDB-Enginesのランキングだけでなく、今日では大手のテクノロジー企業やクラウド企業の多くが、標準的なPostgreSQLやその派生のサポートを提供しているという事実からも明らかです。

2021年12月17日公開

オンデマンド(動画)セミナー

    • PostgreSQLに関連するセミナー動画を公開中。いつでもセミナーをご覧いただけます。
      • 【事例解説】運送業務改革をもたらす次世代の運送業界向けDXプラットフォームの構築
      • ハイブリッドクラウドに最適なOSSベースのデータベースご紹介

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ