MAGAZINE

ルーターマガジン

データベース

PostgreSQLでtext/byteaを圧縮する方法まとめ — STORAGE戦略×圧縮アルゴリズムの選定フローチャート付き

2026.08.06

目次

はじめに

PostgreSQLはtextbyteaのような可変長データを、必要に応じて圧縮したりテーブル本体とは別の領域(TOAST)に退避したりして格納している。この仕組みは自動で動くため普段は意識しなくてよいが、

  • ログやJSONのような巨大なテキストカラムを持つテーブルの肥大化を抑えたい
  • PostgreSQL 14で追加されたlz4圧縮と、従来のpglzのどちらを使うべきか判断したい
  • そもそも「圧縮された場合とされない場合でどれだけ差が出るのか」を数字で把握したい

といった場面では、内部動作を理解しておく価値がある。本記事では実際にPostgreSQL 17をDocker上で動かし、同一データセットに対して4種類のストレージ/圧縮設定を試して容量・速度を比較した。

検証に使ったSQLはすべて本記事内末尾に載せている

PostgreSQLにおける「カラムごとの圧縮」の全体像

PostgreSQLの圧縮はテーブル単位ではなく、カラム(正確には値がTOAST可能かどうか)単位で決まる。ポイントは2つのレイヤーに分かれていることだ。

1. ストレージ戦略(STORAGE) — 大きい値をどう格納するか

PostgreSQLはテーブルのデータを8KB単位の「ページ」に格納している。1行の値がこのページに収まらないほど大きい場合、PostgreSQLは次の2つの手段のどちらか(または両方)を使ってなんとか収めようとする。

  • 圧縮する: 値を圧縮して小さくし、そのままテーブル本体(ヒープ)に格納する
  • TOASTする(行外保存): 値をテーブル本体には置かず、TOASTテーブルという別の場所に分割して格納し、テーブル本体には「そこを見に行けばある」という参照(ポインタ)だけを残す

STORAGE属性は、カラムごとに「圧縮を試みるか」「TOAST(行外保存)を許可するか」をそれぞれON/OFFで指定する設定。この2つは独立したスイッチなので、組み合わせは4パターンある。

STORAGE値 圧縮を試みるか TOAST(行外保存)を許可するか 具体的な挙動 どんなカラムで使われるか
PLAIN しない しない 圧縮もTOASTも一切せず、常にテーブル本体にそのまま格納する。値がページに収まらないとINSERTがエラーになる intbooleanなど、元々サイズが固定で小さい型のデフォルト
MAIN する 基本的にはしない(最後の手段) まず圧縮を試みる。圧縮してもページに収まらない場合のみ、最終手段としてTOASTする numericなど、なるべくテーブル本体に残しておきたい型
EXTENDED する する まず圧縮を試み、それでも大きければ積極的にTOASTへ退避する(最もよく使われる標準設定) textbyteaなど可変長型のデフォルト
EXTERNAL しない する 圧縮はせず、大きい値はそのままTOASTへ退避する。圧縮のCPUコストをかけたくない場合に使う 大きな値を扱うが圧縮処理の負荷を避けたいカラム

カラムのSTORAGE設定は後から変更できる。

ALTER TABLE t ALTER COLUMN col SET STORAGE EXTERNAL;

2. 圧縮アルゴリズム(COMPRESSION) — 「どう圧縮するか」

STORAGEが圧縮を許す設定(MAIN/EXTENDED)の場合、実際にどのアルゴリズムで圧縮するかを選べる。PostgreSQL 14以降、カラム単位で指定可能になった。

圧縮方式 対応バージョン 特徴
pglz 全バージョン PostgreSQL独自実装。追加ビルド不要。圧縮率重視
lz4 PostgreSQL 14+ --with-lz4ビルドが必要(公式イメージ・主要パッケージは対応済み)。圧縮/伸長が高速
-- カラム単位で指定
ALTER TABLE t ALTER COLUMN col SET COMPRESSION lz4;

-- 新規テーブル作成時
CREATE TABLE t (col text COMPRESSION lz4);

-- デフォルトを変更(以降作成されるカラムに適用)
SET default_toast_compression = 'lz4';

値が実際にどう圧縮されているかはpg_column_compression()関数で確認できる。無圧縮ならNULLが返る。

3. STORAGEとCOMPRESSIONの組み合わせ早見表

ここまでの内容を踏まえた、組み合わせごとのメリット・デメリットのまとめ。MAINの行は本記事では実測しておらず、PostgreSQLのドキュメントに基づく一般的な特性として記載している(それ以外の行は次章以降の実測結果に基づく)。

STORAGE COMPRESSION メリット デメリット
PLAIN 圧縮不可 圧縮・TOASTの処理が一切ないため読み書きが最も単純で軽い 容量削減効果はゼロで最も容量を消費する。値がページ(8KB)に収まらないとINSERTがエラーになる
EXTERNAL 圧縮不可 圧縮のCPU負荷をかけずに大きな値を扱える。ヒープ(テーブル本体)が小さく保たれる 容量削減効果はゼロ。TOASTへのアクセスの分だけ読み取りに追加コストがかかることがある(本検証では圧縮する方式より遅かった)
MAIN(未実測) pglzまたはlz4 圧縮を優先しつつ、可能な限りTOASTを避けてインラインに残そうとする。頻繁にアクセスする列を行内に留めたい場合に有利 値が大きいと結局TOASTされることがあり、EXTENDEDとの違いが体感しにくい
EXTENDED(デフォルト) pglz 追加設定不要・互換性の心配がない。圧縮率はlz4よりわずかに高い(本検証で93.0%削減) lz4より圧縮・伸長が遅い(本検証でINSERT時間が約3倍)
EXTENDED(デフォルト) lz4 圧縮・伸長がpglzよりずっと速い(本検証でINSERT時間が約1/3)。圧縮率もpglzとほぼ同等(本検証で94.1%削減) PostgreSQL 14以降限定。--with-lz4ビルドが必要(主要ディストリ・公式イメージは対応済み)

検証方法

環境: PostgreSQL 17.5(Dockerイメージpostgres:17、データはtmpfs上でディスクI/Oの影響を排除)

データセット: 2種類のテキストを各2000行、1行3000バイトで用意した。

  • compressible: 同一文を繰り返した文字列(ログ本文やJSONのような「圧縮の効きやすいデータ」を想定)
  • random: md5()で生成したランダムhex文字列(UUID・ハッシュ値・暗号化済みデータのような「圧縮の効きにくいデータ」を想定)

測定項目:

  • pg_column_size() によるカラムの実格納サイズ(インライン圧縮 or TOAST後の実サイズ)
  • pg_relation_size() / pg_total_relation_size() によるテーブル全体・TOAST込みのサイズ
  • INSERT・全件スキャンの所要時間(参考値)

比較した4パターン:

STORAGEとCOMPRESSIONは独立した設定なので、本来は組み合わせを自由に選べる。今回は「COMPRESSIONの効果を見るペア」と「STORAGEの効果を見るペア」を1つずつ用意した。

  1. STORAGE EXTENDED(デフォルト)+ COMPRESSION pglz(PostgreSQL標準の圧縮方式でカラムの値を圧縮する設定)
  2. STORAGE EXTENDED(デフォルト)+ COMPRESSION lz4(PostgreSQL 14以降で使える圧縮方式でカラムの値を圧縮する設定。1.と比べることでCOMPRESSIONの違いだけを比較できる)
  3. STORAGE PLAIN(圧縮不可・非TOASTのベースライン。圧縮もTOASTも行わず常にテーブル本体にそのまま格納する設定)
  4. STORAGE EXTERNAL(圧縮不可・TOASTありのベースライン。圧縮はしないがサイズが大きい値はTOASTへ退避する設定。3.と比べることでSTORAGEの違いだけを比較できる)

以降の表では便宜上pglz / lz4 / plain / externalという4つのラベルで結果を並べているが、これらは同一の軸を4段階で比較しているわけではない。pglzlz4はSTORAGE EXTENDED固定でCOMPRESSIONだけを変えた比較、plainexternalはCOMPRESSIONなし固定でSTORAGEだけを変えた比較であることに注意してほしい(各表にSTORAGE列とCOMPRESSION列を分けて明記している)。

結果

事実(実測値)のみをここにまとめる。解釈・考察は次章「考察」で行う。

カラムの圧縮率

STORAGE COMPRESSION データ種別 行数 平均元サイズ(バイト) 平均格納後サイズ(バイト) 圧縮率(格納後÷元)
EXTENDED pglz compressible 2000 3000 209 0.070
EXTENDED pglz random 2000 3000 3000 1.000
EXTENDED lz4 compressible 2000 3000 178 0.059
EXTENDED lz4 random 38 3000 2990 0.997
EXTENDED lz4 random 1962 3000 3000 1.000
PLAIN 圧縮不可 compressible 2000 3000 3004 1.001
PLAIN 圧縮不可 random 2000 3000 3004 1.001
EXTERNAL 圧縮不可 compressible 2000 3000 3000 1.000
EXTERNAL 圧縮不可 random 2000 3000 3000 1.000

lz4のrandomデータのみ、2000行中38行(1.9%)が2990バイトまで(わずかに)圧縮され、残り1962行は無圧縮のままだった。

テーブル全体のサイズ

STORAGE COMPRESSION heap toast total 無圧縮比(無圧縮方式=1.00とした場合)
EXTENDED pglz 632 kB 8272 kB 8904 kB 0.54倍
EXTENDED lz4 568 kB 8272 kB 8840 kB 0.54倍
PLAIN 圧縮不可 16 MB 144 kB 16 MB 1.00倍
EXTERNAL 圧縮不可 256 kB 16 MB 16 MB 1.00倍

条件: compressible 2000行 + random 2000行(各3000バイト/行)を同一テーブルに格納。

INSERT所要時間(参考値)

STORAGE COMPRESSION compressibleデータ2000行のINSERT randomデータ2000行のINSERT
EXTENDED pglz 70.974 ms 500.937 ms
EXTENDED lz4 25.685 ms 358.381 ms
PLAIN 圧縮不可 18.880 ms 283.673 ms
EXTERNAL 圧縮不可 38.283 ms 301.305 ms

randomデータのINSERT時間はテストデータ生成関数(md5()の繰り返し呼び出し)のコストが支配的で、圧縮処理そのものの所要時間を表していない。compressibleデータのINSERT時間の方が、圧縮処理コストの比較として意味を持つ。

伸長(読み取り)速度

同一データ(compressible、2000行)をgenerate_series(1,20)とクロス結合して4万回分読み取りさせ、所要時間を4方式すべてで比較した(length()は値を取得しないと計算できないため、読み取り処理を強制的に発生させるために使っている)。実行したクエリ:

SELECT sum(length(payload)) FROM t_pglz,     generate_series(1,20) g WHERE kind = 'compressible';
SELECT sum(length(payload)) FROM t_lz4,      generate_series(1,20) g WHERE kind = 'compressible';
SELECT sum(length(payload)) FROM t_plain,    generate_series(1,20) g WHERE kind = 'compressible';
SELECT sum(length(payload)) FROM t_external, generate_series(1,20) g WHERE kind = 'compressible';

ブレを確認するため各2回実行した結果:

テーブル STORAGE / COMPRESSION 1回目 2回目
t_pglz EXTENDED / pglz 248.9 ms 226.4 ms
t_lz4 EXTENDED / lz4 258.0 ms 197.6 ms
t_plain PLAIN / 圧縮不可 213.5 ms 230.9 ms
t_external EXTERNAL / 圧縮不可 323.2 ms 306.5 ms

t_externalだけが他の3つより明確に遅い(300ms台 vs 190〜260ms台)。

考察

事実に対する解釈・推奨をここにまとめる。数値の再掲は最小限にとどめ、詳細は「結果」章を参照。

データの性質による圧縮効果の違い

繰り返しの多いテキストはpglz・lz4どちらでも9割以上圧縮できた一方、ランダムなhex文字列はほとんど圧縮できなかった。lz4で38行だけわずかに圧縮できたのは、ランダム生成の偶然の繰り返しパターンを拾えた程度と考えられる。これはPostgreSQLが「圧縮を試みて効果がなければ諦めて無圧縮のまま格納する」という挙動を取っているためで、圧縮方式の選択以前に、そのカラムに入るデータが繰り返しパターンを含みやすいかどうかが効果を左右する。ログ・JSON・自然文なら効果が出やすく、UUID・ハッシュ値・暗号化済みデータではほぼ効果がない。

テーブルサイズへの影響

同一データ(圧縮できるデータとできないデータを半々に混ぜた条件)で、pglz/lz4は無圧縮の2方式に対して約46%(0.54倍)までテーブルサイズを抑えられた。ただしこの削減率は「半分は圧縮可能、半分は不可能」という本検証条件に依存する数字であり、実データが繰り返しの多いテキストに寄っているほど削減効果は大きく、高エントロピーなカラムが多いほど効果は小さくなると考えられる。

plainexternalは最終的な合計サイズはどちらも16MBとほぼ同じだが、データの置き場所(ヒープかTOASTか)が全く異なる点が興味深い。plainは全データがテーブル本体(ヒープ)に載るためヒープスキャンが重くなりやすく、externalはヒープが小さく保たれる代わりにTOASTアクセスのオーバーヘッドがある。運用上はヒープが小さい方がシーケンシャルスキャンやVACUUMが軽くなる利点がある。

pglz vs lz4:速度の違い

圧縮率の差はpglz 93.0% / lz4 94.1%とごくわずかだったのに対し、compressibleデータのINSERT時間はlz4がpglzの約1/3で完了しており、明確な差が見られた。これは「lz4は圧縮率よりも速度を優先したアルゴリズム」という一般的な特性と一致する。

読み取り速度を左右するのは「展開コスト」より「インラインかTOASTか」

読み取り速度を4方式で比較すると、興味深い傾向が見える。pglz・lz4・plainの3方式はいずれも190〜260ms台で大差ないのに対し、externalだけが300ms台と明確に遅い。

理由は「結果」章の圧縮率の表からも説明できる。compressibleデータはpglz(209バイト)・lz4(178バイト)どちらもTOASTの閾値(約2KB)を大きく下回るため、圧縮後の値はテーブル本体にインライン格納される。plainは無圧縮のままだがSTORAGE設定上そもそもTOASTされず、常にインラインである。つまりpglz・lz4・plainの3方式は「圧縮されているかどうかに関わらず、値がテーブル本体にインラインで載っている」という点で共通しており、読み取り時はヒープページを読むだけで完結する。

一方externalは無圧縮のままTOASTへ退避されるため、読み取りのたびにTOASTテーブルへの追加アクセスが発生する。この検証結果からは、読み取り速度に効いているのは圧縮アルゴリズムの展開コストの差ではなく、値がインラインに収まっているかTOASTに追い出されているかの違いが支配的だと言える。言い換えると、「圧縮するとCPU負荷がかかって読み取りが遅くなるはず」という直感は、少なくとも圧縮後にインライン格納へ収まるケースでは当てはまらず、むしろTOASTアクセスを回避できる分だけ有利に働く。

実務への示唆

  1. 圧縮方式を選ぶ前に、データの性質を確認する。 「圧縮すれば必ず容量が減る」わけではないため、対象カラムが繰り返しパターンを含みやすいデータか、高エントロピーなデータかを見極める。
  2. pglz vs lz4は「容量 vs 速度」のトレードオフとして考える。 圧縮率の差はわずかなので、書き込み・読み取りが頻繁なテーブルはlz4、圧縮率をわずかでも詰めたい・互換性を優先したいならpglzという選び方になる。PostgreSQL 14以降ならカラム単位で使い分けられる。
  3. STORAGE設定と組み合わせて設計する。 圧縮に成功した値はTOASTを回避してインライン格納されるため、ヒープが小さく保たれる。無圧縮運用が必要な場合は、PLAIN(常にインライン、ページサイズ制約あり)かEXTERNAL(TOASTするがヒープは小さい)かで設計が変わる。
  4. 実測して決める価値がある。 本記事のように実際のデータに近いサンプルでpg_column_size() / pg_total_relation_size() / pg_column_compression()を使えば、机上の想定ではなく実測ベースで圧縮方式を選定できる。

設定の決め方:フローチャート

ここまでの内容を、はい/いいえの質問だけで設定にたどり着けるフローチャートにまとめた。あくまで本記事の実測結果に基づく目安であり、実際のデータ・アクセスパターンで異なる場合は実測して調整してほしい。

早見表:結果と考察のまとめ

数値(結果)と一言でいうと何が言えるか(考察の要約)を1つの表にまとめたもの。詳細な数値の根拠は「結果」「考察」の各章を参照。

STORAGE COMPRESSION 圧縮しやすいデータの圧縮率 テーブル全体サイズ(無圧縮比) 圧縮速度(compressibleデータのINSERT時間) 伸長(読み取り)速度 一言でいうと
EXTENDED pglz 93.0%削減(209バイト) 0.54倍 70.974 ms(基準) 226〜249ms 追加設定不要でとにかく容量を減らしたいなら、まずこれ
EXTENDED lz4 94.1%削減(178バイト) 0.54倍 25.685 ms(pglzの約1/3) 198〜258ms(pglzとの有意差なし) PostgreSQL 14以降限定だが、書き込みが多い・CPU負荷を抑えたいテーブルに向く
PLAIN 圧縮不可 圧縮なし(3004バイト) 1.00倍 18.880 ms 214〜231ms(pglz/lz4と同水準) 固定長・小さい値向け。大きいtext/byteaには不向き
EXTERNAL 圧縮不可 圧縮なし(3000バイト) 1.00倍 38.283 ms 307〜323ms(4方式中で最も遅い) 圧縮のCPU負荷を避けたい場合だけのベースライン。読み取り速度は最も不利

再現手順

Dockerが使える環境であれば、以下の手順だけで本記事の「結果」章と同じ実測値を再現できる。

1. 検証用PostgreSQLコンテナを起動する

docker run -d --name pgcompress_test -e POSTGRES_PASSWORD=postgres \
  -p 15432:5432 --tmpfs /var/lib/postgresql/data postgres:17

# 起動待ち
until docker exec pgcompress_test pg_isready -U postgres >/dev/null 2>&1; do sleep 1; done

--tmpfsはデータをメモリ上に置く指定で、ディスクI/Oの影響を排除するため、かつコンテナを消せば自動的にデータも消える使い捨て構成にするために付けている。

2. 検証用SQLを実行する

以下のSQLをファイル(例: bench.sql)に保存し、PGPASSWORD=postgres psql -h localhost -p 15432 -U postgres -d postgres -f bench.sqlで実行する。

-- --- テストデータ生成関数(ASCII文字のみを使い、文字数=バイト数として扱えるようにしている) ---

-- 圧縮が効きやすいテキスト(同一文の繰り返し。ログ本文やJSON等を想定)
CREATE OR REPLACE FUNCTION gen_compressible_text(target_len int) RETURNS text AS $$
  SELECT left(
    repeat('The quick brown fox jumps over the lazy dog. PostgreSQL column-level compression benchmark sample payload repeated many times for testing purposes. ', 100),
    target_len
  );
$$ LANGUAGE sql IMMUTABLE;

-- 圧縮が効きにくいテキスト(ランダムhex文字列。UUIDやハッシュ値、暗号化済みデータを想定)
CREATE OR REPLACE FUNCTION gen_random_text(target_len int) RETURNS text AS $$
  SELECT left(string_agg(md5(random()::text || i), ''), target_len)
  FROM generate_series(1, (target_len / 32) + 1) AS i;
$$ LANGUAGE sql VOLATILE;

-- --- 1. COMPRESSION pglz ---
CREATE TABLE t_pglz (id serial PRIMARY KEY, kind text NOT NULL, payload text COMPRESSION pglz);
INSERT INTO t_pglz (kind, payload) SELECT 'compressible', gen_compressible_text(3000) FROM generate_series(1, 2000);
INSERT INTO t_pglz (kind, payload) SELECT 'random',       gen_random_text(3000)       FROM generate_series(1, 2000);

-- --- 2. COMPRESSION lz4 ---
CREATE TABLE t_lz4 (id serial PRIMARY KEY, kind text NOT NULL, payload text COMPRESSION lz4);
INSERT INTO t_lz4 (kind, payload) SELECT 'compressible', gen_compressible_text(3000) FROM generate_series(1, 2000);
INSERT INTO t_lz4 (kind, payload) SELECT 'random',       gen_random_text(3000)       FROM generate_series(1, 2000);

-- --- 3. STORAGE PLAIN(無圧縮・非TOASTのベースライン) ---
CREATE TABLE t_plain (id serial PRIMARY KEY, kind text NOT NULL, payload text);
ALTER TABLE t_plain ALTER COLUMN payload SET STORAGE PLAIN;
INSERT INTO t_plain (kind, payload) SELECT 'compressible', gen_compressible_text(3000) FROM generate_series(1, 2000);
INSERT INTO t_plain (kind, payload) SELECT 'random',       gen_random_text(3000)       FROM generate_series(1, 2000);

-- --- 4. STORAGE EXTERNAL(無圧縮・TOASTありのベースライン) ---
CREATE TABLE t_external (id serial PRIMARY KEY, kind text NOT NULL, payload text);
ALTER TABLE t_external ALTER COLUMN payload SET STORAGE EXTERNAL;
INSERT INTO t_external (kind, payload) SELECT 'compressible', gen_compressible_text(3000) FROM generate_series(1, 2000);
INSERT INTO t_external (kind, payload) SELECT 'random',       gen_random_text(3000)       FROM generate_series(1, 2000);

VACUUM ANALYZE;

-- --- 5. カラムの圧縮率を確認(「結果」章の表と同じ内容が出る) ---
-- storage/compression列を分けているのは、pglz/lz4がSTORAGE EXTENDED固定でCOMPRESSIONだけを変えた比較、
-- plain/externalがCOMPRESSIONなし固定でSTORAGEだけを変えた比較であることを明示するため。
SELECT 'EXTENDED' AS storage, 'pglz'   AS compression, kind, count(*) AS rows, avg(pg_column_size(payload))::int AS avg_stored_bytes FROM t_pglz GROUP BY kind
UNION ALL
SELECT 'EXTENDED', 'lz4',    kind, count(*), avg(pg_column_size(payload))::int FROM t_lz4      GROUP BY kind
UNION ALL
SELECT 'PLAIN',    '圧縮不可', kind, count(*), avg(pg_column_size(payload))::int FROM t_plain    GROUP BY kind
UNION ALL
SELECT 'EXTERNAL', '圧縮不可', kind, count(*), avg(pg_column_size(payload))::int FROM t_external GROUP BY kind
ORDER BY storage, compression, kind;

-- --- 6. テーブル全体のサイズを確認 ---
SELECT
  'EXTENDED' AS storage,
  'pglz'     AS compression,
  pg_size_pretty(pg_relation_size('t_pglz'))                                       AS heap,
  pg_size_pretty(pg_total_relation_size('t_pglz') - pg_relation_size('t_pglz'))     AS toast,
  pg_size_pretty(pg_total_relation_size('t_pglz'))                                 AS total
UNION ALL
SELECT 'EXTENDED', 'lz4',
  pg_size_pretty(pg_relation_size('t_lz4')),
  pg_size_pretty(pg_total_relation_size('t_lz4') - pg_relation_size('t_lz4')),
  pg_size_pretty(pg_total_relation_size('t_lz4'))
UNION ALL
SELECT 'PLAIN', '圧縮不可',
  pg_size_pretty(pg_relation_size('t_plain')),
  pg_size_pretty(pg_total_relation_size('t_plain') - pg_relation_size('t_plain')),
  pg_size_pretty(pg_total_relation_size('t_plain'))
UNION ALL
SELECT 'EXTERNAL', '圧縮不可',
  pg_size_pretty(pg_relation_size('t_external')),
  pg_size_pretty(pg_total_relation_size('t_external') - pg_relation_size('t_external')),
  pg_size_pretty(pg_total_relation_size('t_external'));

出力結果の例

上記のSQLをまっさらな環境で実行すると、次のような出力になる(CREATE TABLE/INSERTのログは省略、実測値は乱数を使うrandomデータの影響で多少前後することがある)。

 storage  | compression |     kind     | rows | avg_stored_bytes
----------+-------------+--------------+------+------------------
 EXTENDED | lz4         | compressible | 2000 |              178
 EXTENDED | lz4         | random       | 2000 |             3000
 EXTENDED | pglz        | compressible | 2000 |              209
 EXTENDED | pglz        | random       | 2000 |             3000
 EXTERNAL | 圧縮不可    | compressible | 2000 |             3000
 EXTERNAL | 圧縮不可    | random       | 2000 |             3000
 PLAIN    | 圧縮不可    | compressible | 2000 |             3004
 PLAIN    | 圧縮不可    | random       | 2000 |             3004
(8 rows)

 storage  | compression |  heap  |  toast  |  total
----------+-------------+--------+---------+---------
 EXTENDED | pglz        | 632 kB | 8272 kB | 8904 kB
 EXTENDED | lz4         | 568 kB | 8272 kB | 8840 kB
 PLAIN    | 圧縮不可    | 16 MB  | 144 kB  | 16 MB
 EXTERNAL | 圧縮不可    | 256 kB | 16 MB   | 16 MB
(4 rows)

(乱数を使うrandomデータの都合で、lz4random行だけ本文中の表とは異なりごく一部の行が圧縮される場合があるが、平均値としてはほぼ同じ結果になる)

1つ目の表が「カラムの圧縮率」、2つ目の表が「テーブル全体のサイズ」に対応しており、本記事の「結果」章で示した数値と一致する(実際に別のまっさらなコンテナで再実行して確認済み)。

「伸長(読み取り)速度」の再現には、上記の4テーブルに対して本文中に載せた以下のクエリをそのまま実行すればよい。

SELECT sum(length(payload)) FROM t_pglz,     generate_series(1,20) g WHERE kind = 'compressible';
SELECT sum(length(payload)) FROM t_lz4,      generate_series(1,20) g WHERE kind = 'compressible';
SELECT sum(length(payload)) FROM t_plain,    generate_series(1,20) g WHERE kind = 'compressible';
SELECT sum(length(payload)) FROM t_external, generate_series(1,20) g WHERE kind = 'compressible';

3. 後片付け

docker rm -f pgcompress_test

(データは--tmpfs上にあるため、コンテナを削除するだけでデータも消える)

付録:検証コマンド早見表

-- 圧縮方式の変更
ALTER TABLE t ALTER COLUMN col SET COMPRESSION lz4;   -- or pglz

-- ストレージ戦略の変更
ALTER TABLE t ALTER COLUMN col SET STORAGE EXTERNAL;  -- or PLAIN / MAIN / EXTENDED

-- 実際の圧縮方式・格納サイズを確認
SELECT pg_column_compression(col), pg_column_size(col) FROM t;

-- テーブル全体のサイズ(TOAST込み)
SELECT pg_size_pretty(pg_total_relation_size('t'));

CONTACT

お問い合わせ・ご依頼はこちらから