Greenplumにおけるテーブル格納方式の設計指針

1. 格納方式の概要

Greenplumでは「行方向/列方向」と「ヒープ/Append-Only(AO)」の2軸でテーブルを設計できる。用途に応じて最適な組み合わせを選ぶことで、更新頻度、読み取りパターン、圧縮率、バックアップ戦略などを最適化できる。

2. ヒープ vs AO

2.1 動作原理

  • ヒープ:PostgreSQL と同じ MVCC ヒープ。UPDATE/DELETE が頻繁な OLTP 向き。WAL(REDO)により時点復旧が可能。
  • AO:追記専用ファイルに新規ブロックを追加し、削除/更新は別ビットマップで管理。ブロックは再利用されないため単行 INSERT は非効率だが、バッチロードには最適。約20バイト/行の可視性情報が不要になる。

2.2 選択基準

観点ヒープ推奨AO推奨
トランザクション粒度小さな単位で頻繁に更新バッチ単位で大量挿入
リカバリ方式時点復旧(PITR)必須増分バックアップで十分
テーブルサイズ小〜中規模(例:マスタデータ)大規模(例:ファクトテーブル)

2.3 DDL例

-- ヒープ
CREATE TABLE customer_dim
( id int PRIMARY KEY, name text )
DISTRIBUTED BY (id);

-- AO(無圧縮)
CREATE TABLE sales_fact
( id bigint, amount numeric )
WITH (appendoptimized=true)
DISTRIBUTED BY (id);

3. 行方向 vs 列方向

3.1 特性比較

項目行方向列方向
格納単位1レコード=連続配置1列=独立ファイル
列読み出し先頭列から順にデコード対象列のみシーク
圧縮可否不可(行の型が混在)可(同型連続値)
ALTER TABLEフルリライト該当列ファイルのみ追加

3.2 選択基準

  • 行方向:SELECT リスト・WHERE で多列を扱う OLTP/明細検索
  • 列方向:集計クエリが列を限定する OLAP/高圧縮が必須
  • 混在:時間軸パーティションで「新規区間=行方向、過去区間=列方向」

3.3 DDL例

-- 列方向 AO
CREATE TABLE page_view
( ts timestamp, user_id bigint, url text )
WITH (appendoptimized=true, orientation=column)
DISTRIBUTED BY (user_id);

4. 圧縮戦略(AO のみ)

4.1 圧縮アルゴリズム

方向レベルアルゴリズム
テーブルZLIB, ZSTD, QUICKLZ
テーブル/列RLE_TYPE, ZLIB, ZSTD, QUICKLZ

4.2 圧縮率 vs 速度

  • QUICKLZ:低圧縮・高速(CPU 負荷小)
  • ZLIB(6):中圧縮・中速(バランス型)
  • ZLIB(9)/ZSTD(19):高圧縮・低速(ストレージ重視)
  • RLE_TYPE:連続同一値に強い(ソート済データ向き)

4.3 圧縮設定例

-- テーブル単位
CREATE TABLE log_large
( id bigint, msg text )
WITH (
  appendoptimized=true,
  compresstype=zstd,
  compresslevel=3
);

-- 列単位
CREATE TABLE metrics
(
  ts timestamp,
  val float8 ENCODING (compresstype=RLE_TYPE, blocksize=65536),
  tag text      ENCODING (compresstype=zlib, compresslevel=6)
)
WITH (appendoptimized=true, orientation=column);

4関数で圧縮率を確認

SELECT get_ao_compression_ratio('log_large');  -- 例:3.19

5. パフォーマンス実験

400列×100万行のテストテーブルを作成し、行ヒープ/行AO/列AO で集計クエリを実行。

-- テーブル作成関数(略)

-- 実行時間比較(例:c2 列で GROUP BY)
行ヒープ 138 ms → 行AO 152 ms → 列AO 107 ms
末尾列でも列AO は 120 ms で最速。

列方向 AO は CPU 効率が高く、特に集計列が少ないクエリで優位性が顕著。

6. 格納方式の照会

-- AO テーブル一覧
SELECT nspname, relname
FROM pg_class c JOIN pg_namespace n ON n.oid = relnamespace
WHERE relstorage IN ('a','c');

-- ヒープ テーブル一覧
SELECT nspname, relname
FROM pg_class c JOIN pg_namespace n ON n.oid = relnamespace
WHERE relstorage = 'h' AND relkind = 'r';

7. ディストリビューション再編成

-- ハッシュキー変更(自動リバランス)
ALTER TABLE sales SET DISTRIBUTED BY (customer_id);

-- ランダム化(データは動かない)
ALTER TABLE sales SET DISTRIBUTED RANDOMLY;

-- 手動リバランス
ALTER TABLE sales SET WITH (REORGANIZE=true);

8. 格納方式の変更手順

CREATE → INSERT → DROP → RENAME の4ステップで移行。

CREATE TABLE sales_col
(LIKE sales)
WITH (appendoptimized=true, orientation=column, compresstype=zstd);
INSERT INTO sales_col SELECT * FROM sales;
DROP TABLE sales;
ALTER TABLE sales_col RENAME TO sales;

9. 列追加と圧縮継承

-- 圧縮列追加
ALTER TABLE sales
  ADD COLUMN discount numeric DEFAULT 0
  ENCODING (compresstype=zlib);

-- パーティション継承例
CREATE TABLE ccddl (i int, j int, k int, l int)
WITH (appendoptimized=true, orientation=column)
PARTITION BY RANGE (j)
SUBPARTITION BY LIST (k)
SUBPARTITION TEMPLATE (
  SUBPARTITION sp1 VALUES (1,2,3),
  COLUMN i ENCODING (compresstype=zlib),
  COLUMN j ENCODING (compresstype=quicklz)
) ( PARTITION p1 START (1) END (10) );

ALTER TABLE ccddl ADD PARTITION p3 START (20) END (30);
-- p3 は sp1 の圧縮設定を自動継承

タグ: Greenplum AOテーブル 列指向 圧縮 ZSTD

6月28日 18:02 投稿