0Pricing
PostgreSQL Performance & Query Optimization · レッスン

TOASTの内部構造と大きな値の格納

PostgreSQLが大きすぎるカラムをどのように格納するかを理解し、圧縮と外部格納のしきい値を調整します。

「TOASTの内部構造と大きな値の格納」はCoddyKit上の無料PostgreSQL Performance & Query Optimizationレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPostgreSQL Performance & Query Optimization学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 PostgreSQL Performance & Query Optimizationコースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

Why TOAST Exists

PostgreSQL stores rows on fixed-size 8 KB pages. A single row cannot span multiple pages, so a wide value (a long text, big jsonb, or bytea) would never fit.

TOAST (The Oversized-Attribute Storage Technique) solves this by compressing oversized columns and, if still too large, slicing them into chunks stored in a separate side table.

  • Keeps the main heap row small and cache-friendly.
  • Lets a logical value far exceed 8 KB (up to ~1 GB).
  • Happens automatically and transparently to your queries.

The TOAST Threshold

TOAST kicks in when a row's total size would exceed TOAST_TUPLE_THRESHOLD, which is 2 KB (one quarter of the 8 KB page) by default.

When that limit is crossed, PostgreSQL compresses and/or moves the largest toastable attributes out of line until the row fits under TOAST_TUPLE_TARGET (also ~2 KB).

Only columns of variable-length types (text, varchar, jsonb, bytea, arrays, etc.) are toastable. Fixed-width types like integer or timestamptz are never toasted.

Finding the TOAST Table

Every table with at least one toastable column gets an associated TOAST table named pg_toast.pg_toast_<oid>. You can locate it from the catalog.

The reltoastrelid column links a heap relation to its TOAST relation; a value of 0 means no TOAST table was created.

SELECT c.relname,
       c.reltoastrelid,
       t.relname AS toast_table
FROM pg_class c
LEFT JOIN pg_class t ON t.oid = c.reltoastrelid
WHERE c.relname = 'documents';

The Four Storage Strategies

Each column has a storage strategy controlling whether it can be compressed and/or moved out of line:

  • PLAIN — no compression, no out-of-line; only valid for non-toastable types.
  • EXTENDED — allow both compression and out-of-line storage (default for most varlena types).
  • EXTERNAL — allow out-of-line but no compression (faster substring access).
  • MAIN — allow compression but keep in the main table unless absolutely necessary.

Inspecting Per-Column Storage

Query pg_attribute.attstorage to see each column's strategy. The codes map to: p=PLAIN, e=EXTERNAL, m=MAIN, x=EXTENDED.

SELECT attname,
       atttypid::regtype AS type,
       CASE attstorage
         WHEN 'p' THEN 'plain'
         WHEN 'e' THEN 'external'
         WHEN 'm' THEN 'main'
         WHEN 'x' THEN 'extended'
       END AS storage
FROM pg_attribute
WHERE attrelid = 'documents'::regclass
  AND attnum > 0
  AND NOT attisdropped;

Changing a Column's Strategy

Use ALTER TABLE ... SET STORAGE to override the default. A common optimization: if you frequently read random substrings of a large bytea (e.g. range reads on a blob), switch to EXTERNAL so values are stored uncompressed and can be partially fetched without decompressing the whole thing.

The new strategy applies only to rows written after the change; existing data is not rewritten until updated.

ALTER TABLE documents
  ALTER COLUMN payload SET STORAGE EXTERNAL;

-- Force a rewrite to apply it to existing rows:
VACUUM FULL documents;

Compression Algorithms: pglz vs lz4

PostgreSQL compresses TOAST values before considering out-of-line storage. Two algorithms are available:

  • pglz — the historic built-in, decent ratio, slower.
  • lz4 — available since PostgreSQL 14, much faster compress/decompress with a slightly lower ratio. Requires the server to be built with lz4 support.

The cluster-wide default is set by default_toast_compression.

SHOW default_toast_compression;

-- Set lz4 cluster-wide (postgresql.conf or per session):
SET default_toast_compression = 'lz4';

Per-Column Compression

From PostgreSQL 14 onward you can set the compression method on individual columns with SET COMPRESSION. This is independent of the storage strategy.

Choose lz4 for hot, large columns where CPU during read/write matters; keep pglz or use EXTERNAL when ratio or substring access dominates.

ALTER TABLE documents
  ALTER COLUMN body SET COMPRESSION lz4;

-- Inspect chosen method per column:
SELECT attname, attcompression
FROM pg_attribute
WHERE attrelid = 'documents'::regclass
  AND attnum > 0;

Tuning the Out-of-Line Target

The reloption toast_tuple_target controls how aggressively PostgreSQL pushes attributes out of line: it sets the size the main tuple is shrunk toward (valid range 128 bytes to ~8160).

Lowering it makes more values go to TOAST sooner, keeping the main heap dense and improving scan performance when the big columns are rarely read. Raising it keeps more data inline.

ALTER TABLE documents
  SET (toast_tuple_target = 512);

-- Verify current reloptions:
SELECT reloptions
FROM pg_class
WHERE relname = 'documents';

Measuring TOAST Footprint

Use the size functions to separate main-table bytes from TOAST bytes. This tells you whether your bloat lives in the heap or in oversized values.

  • pg_table_size — heap + TOAST + their indexes' TOAST, excluding regular indexes.
  • pg_relation_size(rel, 'main') — just the main fork.
SELECT
  pg_size_pretty(pg_relation_size('documents'))        AS heap,
  pg_size_pretty(
    pg_total_relation_size(reltoastrelid)
  )                                                     AS toast,
  pg_size_pretty(pg_total_relation_size('documents'))  AS total
FROM pg_class
WHERE relname = 'documents';

Practical Performance Implications

TOAST is invisible until it isn't. Key effects to remember:

  • Reading a toasted column triggers extra index lookups into the TOAST table and possible decompression — avoid SELECT * when you only need small columns.
  • Values stay TOASTed across UPDATEs that don't touch them, so unrelated updates are cheap.
  • EXTERNAL enables efficient substr() / range reads on large uncompressed blobs.
  • Switching pglz to lz4 can cut write CPU dramatically on insert-heavy large-value workloads.

Quick Check

You have a table whose large bytea column is read mostly via substr() on small byte ranges, and these reads are slow because each access decompresses the entire value. Which single change best fixes this?

Recap

You learned how PostgreSQL handles oversized values:

  • TOAST triggers when a row would exceed the ~2 KB threshold, compressing then moving large varlena columns into pg_toast.* tables.
  • Four strategies — PLAIN, MAIN, EXTENDED (default), EXTERNAL — control compression and out-of-line placement, set via ALTER TABLE ... SET STORAGE.
  • lz4 (PG14+) offers faster compression than pglz; choose per column with SET COMPRESSION or cluster-wide via default_toast_compression.
  • toast_tuple_target tunes how eagerly values leave the heap; size functions reveal how much storage lives in TOAST.
  • Pick EXTERNAL for substring/range reads, lz4 for write-heavy large values, and avoid SELECT * to skip needless detoasting.

よくある質問

「TOASTの内部構造と大きな値の格納」レッスンは無料ですか?

はい。「TOASTの内部構造と大きな値の格納」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、PostgreSQL Performance & Query Optimizationコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 PostgreSQL Performance & Query Optimizationコースには全4レッスンが含まれています。

「TOASTの内部構造と大きな値の格納」で何を学びますか?

PostgreSQLが大きすぎるカラムをどのように格納するかを理解し、圧縮と外部格納のしきい値を調整します。 ブラウザで直接実行するハンズオンコードでPostgreSQL Performance & Query Optimizationを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

PostgreSQL Performance & Query Optimizationを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPostgreSQL Performance & Query Optimizationは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「TOASTの内部構造と大きな値の格納」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPostgreSQL Performance & Query Optimizationレッスンでコードを書いて実行できますか?

はい。すべてのPostgreSQL Performance & Query Optimizationレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. テーブルとインデックスの膨張を正確に測定する
  2. pg_repackによる領域の再利用
  3. 更新の多いテーブルのFillfactorチューニング
  4. TOASTの内部構造と大きな値の格納
← PostgreSQL Performance & Query Optimizationに戻る