LZ4 TOAST圧縮 – PostgreSQL 14でコミットされた機能の紹介:技術者Blog
PostgreSQLインサイド

唐 海英

南京富士通南大軟件技術有限公司
開発事業本部デジタルソリューション事業部

はじめに

新しい列圧縮オプションであるLZ4がPostgreSQL 14に導入されました。これは、TOASTの既存のPGLZよりも高速な圧縮を提供します。この記事では、新しいLZ4圧縮を使用する場合の使用方法と性能について説明します。

背景


PostgreSQLでは、データを保存するための基本単位は「ページ」であり、各ページのサイズはデフォルトで8キロバイトです。基本的に、1行のデータについてページをまたいで保存することはできません。しかし、データ型によっては可変長のものがあり、1ページのサイズを超える場合があります。この制限に対応するために、大きなフィールド値は圧縮されたり、複数の物理的な行に分割されたりします。この技術はTOAST(The Oversized-Attribute Storage Technique)と呼ばれています。

デフォルトでは、テーブルに可変長の列があり、行データのサイズがTOAST_TUPLE_THRESHOLD(通常は2キロバイト)を超えた場合にのみ、TOASTの機構が利用されます。まず、データが圧縮され、それでもまだデータが大きすぎる場合は、行外に格納されます。列の格納戦略がEXTERNAL / PLAINに指定されている場合のみ、圧縮は無効になることに注意してください。

PostgreSQL 13までは、TOASTはPostgreSQLの組み込みアルゴリズムであるPGLZという1つの圧縮アルゴリズムしかサポートしていませんでした。周知のとおり、PGLZよりも高速で、より高い圧縮率を持つ圧縮アルゴリズムは他にもたくさんありますが、それらはPostgreSQL 14以前では利用できませんでした。PostgreSQL 14では、高速な可逆圧縮アルゴリズムで知られるLZ4圧縮が追加されました。これにより、TOASTの圧縮・解凍の速度向上に役立つことが期待できます。

LZ4の使い方


PostgreSQL 14で新たに追加されたLZ4圧縮機能を使用するための手順を説明します。

まず、LZ4関連のライブラリーをOSにインストールし、PostgreSQLのコンパイルやパッケージングの際に「--with-lz4」オプションを指定します。

次に、PostgreSQLインスタンスでは、GUCパラメーター「default_toast_compression」を設定することにより、TOASTの圧縮アルゴリズムを指定できます。設定ファイルpostgresql.confを編集して圧縮アルゴリズムにLZ4を設定するか、「SET」コマンドを使用して現在のクライアント接続(セッション)の圧縮アルゴリズムを変更します。

また、テーブルの作成時に列の圧縮アルゴリズムをLZ4に指定することもできます。同様に、ALTER TABLEコマンドを使用して、すでに作成されたテーブルの圧縮アルゴリズムを変更することもできますが、新たに変更された圧縮アルゴリズムはALTER TABLEコマンドの実行後に挿入されたデータに対してのみ有効になります。

以下に、LZ4を設定・使用する例を示します。

例1)デフォルトの圧縮アルゴリズムとして「LZ4」を設定する方法

postgres=# SET default_toast_compression=lz4;
SET

例2)CREATE TABLE文で列ごとの圧縮アルゴリズムを指定する方法

postgres=# CREATE TABLE tbl (id int, col1 text COMPRESSION pglz, col2 text COMPRESSION lz4, col3 text);
CREATE TABLE
postgres=# ¥d+ tbl
                                           Table "public.tbl"
 Column |  Type   | Collation | Nullable | Default | Storage  | Compression | Stats target | Description
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
 id     | integer |           |          |         | plain    |             |              |
 col1   | text    |           |          |         | extended | pglz        |              |
 col2   | text    |           |          |         | extended | lz4         |              |
 col3   | text    |           |          |         | extended |             |
Access method: heap

describeコマンドの'¥d+'を使って、カラムの圧縮アルゴリズムを表示できます。カラムが圧縮をサポートしていない場合や圧縮アルゴリズムが指定されていない場合は、空白が表示されます。
上記の例では、カラム「id」は圧縮をサポートしておらず、カラム「col1」はPGLZ、カラム「col2」はLZ4、カラム「col3」は圧縮アルゴリズムが指定されていないため、デフォルトの圧縮アルゴリズムが使用されます。

例3)ALTER TABLE文で列の圧縮アルゴリズムを変更する方法

postgres=# INSERT INTO tbl VALUES (1, repeat('abcdefg',1000), repeat('abcdefg',1000),repeat('abcdefg',1000));
INSERT 0 1
postgres=# ALTER TABLE tbl ALTER COLUMN col1 SET COMPRESSION lz4;
ALTER TABLE
postgres=# INSERT INTO tbl VALUES (2, repeat('abcdefg',1000), repeat('abcdefg',1000),repeat('abcdefg',1000));
INSERT 0 1
postgres=# SELECT id, pg_column_compression(id), pg_column_compression(col1),  pg_column_compression(col2), pg_column_compression(col3) FROM tbl;
 id | pg_column_compression | pg_column_compression | pg_column_compression | pg_column_compression
----+-----------------------+-----------------------+-----------------------+-----------------------
  1 |                       | pglz                  | lz4                   | lz4
  2 |                       | lz4                   | lz4                   | lz4
(2 rows)

上の図では、1行目の列「col1」は、圧縮方法をPGLZからLZ4に変更しても、依然としてPGLZで圧縮されていることがわかります。つまり、既存のデータの圧縮方法は変わらないということです。

注意事項

  • CREATE TABLE .... AS ... や INSERT INTO ... SELECT ... を使って他のテーブルからデータを挿入する場合、挿入されるデータの圧縮方法は元のデータと同じです。
  • LZ4をサポートする一方で、pg_dumpとpg_dumpallには「--no-toast-compression」というオプションが追加され、圧縮方式をダンプ情報に出力しません。

性能比較


ここでは、LZ4とPGLZを圧縮率と圧縮速度の両面で比較するテストを行いました。参考値として、非圧縮データ(データ型の格納戦略に「EXTERNAL」を指定した場合)のテスト結果も併記しました。非圧縮データの場合、圧縮・解凍にかかる時間はありませんが、その分、データの読み書きにかかる時間が長くなります。

準備

テストには以下のデータを使用し、表中の見出しとして以下のように記載しています。

  • pg doc:PostgreSQLドキュメント(1行につき1つのHTMLファイル)
  • Silesia Corpus(注1)から提供されたデータ
    • html:HTML
    • English text:テキスト
    • src:ソースコード
    • exe:実行可能なバイナリー
    • picture:画像

テストサーバーのプロセッサースペックは、Intel® Xeon® Silver 4210 CPU @2.20GHz、10コア / 20スレッド / 2ソケットです。
SQLの実行時間を計測するために「pgbench」を使用し、テーブルのサイズを確認するためにシステム関数「pg_table_size」を使用しています。また、各テストの前に「VACUMM FULL」コマンドを実行し、データストレージをクリアしています。

圧縮率

PGLZとLZ4の圧縮率は、データ内の重複項目に関係しており、重複項目が多いほど圧縮率は高くなります。
しかし、圧縮率が低い場合、データサイズが閾値に達しても圧縮は行われません。なぜなら、この場合、圧縮しても効果的にディスク容量を節約できず、逆に解凍に余分な時間とリソースがかかってしまうからです。
PostgreSQL 14の現在のソースコードによると、PGLZでは25%以上の圧縮率が必要とされ、LZ4では圧縮データが非圧縮データよりも大きくならないことが必要とされています。

図1では、LZ4とPGLZの圧縮アルゴリズムを使用したテーブルサイズを非圧縮のテーブルサイズと比較しました。ほとんどのケースで、PGLZの圧縮率がわずかに優れていることがわかります。平均して、PGLZの圧縮率は2.23で、LZ4の圧縮率は2.07です。つまり、LZ4と比較して、PGLZを使用することで約7%のディスク容量を節約できます。

図1:テーブルサイズの比較
図1:テーブルサイズの比較

圧縮 / 解凍速度

TOASTのデータは、挿入 / 検索される際に圧縮 / 解凍されます。そこで、いくつかのSQL文を実行して、異なる圧縮アルゴリズムが圧縮 / 解凍速度に与える影響を見てみました。

INSERT文

図2は、INSERT文の実行にかかった時間を示しています。
これによると、LZ4は圧縮されていないものよりもデータの挿入にわずかに時間がかかるのに対し、PGLZを使うとデータの挿入にかかる時間が大幅に増加することがわかりました。平均すると、LZ4の圧縮にかかる時間は、PGLZの圧縮にかかる時間の約20%に過ぎません。これは非常に大きな改善です。

図2:INSERT文の性能比較
図2:INSERT文の性能比較

SELECT文

図3は、SELECT文の実行にかかった時間を示しています。
データを問い合わせている間、LZ4はPGLZと比較して約20%の時間短縮を実現しており、非圧縮と比較しても明らかな増加は見られないことがわかります。解凍にかかる時間は非常に少なくなっていることが伺えます。

図3:SELECT文の性能比較
図3:SELECT文の性能比較

16個のクライアントからのINSERT文

もう1つの一般的なシナリオは、複数のクライアントからデータベースにアクセスすることです。
図4の結果からわかるように、16個のクライアントがある場合に、1つの大きなファイル(HTML、テキスト、ソースコード、実行可能なバイナリー、画像)をLZ4で圧縮したとき、PGLZに比べて60%から70%改善され、複数の小さなファイル(PostgreSQL文書)を挿入したときにも、わずかながら改善が見られました。
また、非圧縮に比べて大幅に改善されていますが、これは圧縮することでディスクに書き込まれるデータ量が減るためだと推測します。

図4:16個のクライアントがある場合のINSERT文の性能比較
図4:16個のクライアントがある場合のINSERT文の性能比較

16個のクライアントからのSELECT文

図5に示すように、複数のクライアントからの問い合わせシナリオでも、ほとんどの場合、LZ4はPGLZよりも優れた性能を発揮します。

図5:16個のクライアントがある場合のSELECT文の性能比較
図5:16個のクライアントがある場合のSELECT文の性能比較

文字列関数

さらに、文字列関連の関数をいくつか呼び出して、テキスト処理の速さを比較しようと試みた結果を図6に示します。ここでも、どちらもLZ4がPGLZを上回っています。また、LZ4圧縮されたデータを使った各関数にかかる時間は、非圧縮データとほとんど変わらないことから、LZ4圧縮は文字列演算の速度にほとんど影響を与えないことがわかりました。使用した文字列関数はそれぞれ以下のとおりです。

  • SQL1:テキストの長さを取得するlength関数を使用したSELECT文
  • SQL2:部分文字列を検索するsubstr関数を使用したSELECT文
  • SQL3:テキストを大文字に更新するupper関数を使用したUPDATE文
  • SQL4:いくつかのテキストを連結するtextcat関数を使用したUPDATE文

図6:文字列関数の性能比較
図6:文字列関数の性能比較

テストの総括

PGLZと比較して、LZ4はTOASTデータの圧縮および解凍においてより効率的です。クエリの実行速度は非圧縮データに近く、データの挿入速度はPGLZに比べて約80%向上し、優れた性能を発揮しています。もちろん、その代償として圧縮率が犠牲になることもありますが、実行速度を向上させたいのであれば、PGLZではなくLZ4を強くお勧めします。
テーブル内のデータが圧縮に適しているかどうかは、事前に検討する必要があります。圧縮率が良くない場合、とりあえずデータの圧縮を試して、諦めることも必要です。これは余計にメモリー資源を浪費することになり、データの挿入速度にも大きく影響するからです。

今後に向けて


TOASTのLZ4圧縮サポートにより、圧縮と解凍の性能が大幅に向上しました。
LZ4に加えて、Zstandardのような優れた圧縮アルゴリズムもあります。Zstandardをサポートすることで、ユーザーはPGLZと比較してさらに優れた圧縮率を得ることができます。また、LZ4 HCでは、平均圧縮速度はLZ4の解凍速度の98.5%ですが、圧縮率は大幅に向上しています。今後のPostgreSQLでは、圧縮アルゴリズムの選択肢が増え、ユーザーがニーズに応じて自由に選択できるようになることを期待しています。
TOASTの他にも、いくつかのシナリオで圧縮を使用する必要があります。私の知る限りでは、WAL(Write Ahead Logging:トランザクション更新ログ)のLZ4圧縮は現在の開発版ですでにサポートされており、非常に期待されています。

2021年11月12日公開

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

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

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

お電話でのお問い合わせ

Webでのお問い合わせ

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

ページの先頭へ