Oracle のテーブル圧縮は、ブロック内の重複データを削減してストレージ使用量を減らす機能です。ストレージコストの削減だけでなく、データがバッファキャッシュに収まりやすくなることでフルスキャン系クエリのパフォーマンスが向上します。
Oracle には大きく分けて2種類のテーブル圧縮があります。基本圧縮(COMPRESS)はダイレクトパス INSERT 専用の圧縮で、バッチ系 DWH 処理に向いています。Advanced Row Compression(ROW STORE COMPRESS ADVANCED)は通常の DML にも対応し、OLTP 環境でも使えます。
この記事でわかること
- 基本圧縮と Advanced Row Compression の違い(適用 DML・ライセンス・効果)
- CREATE TABLE … COMPRESS / ROW STORE COMPRESS ADVANCED でテーブルを作成する方法
- 基本圧縮がダイレクトパス INSERT でしか効かない理由
- ALTER TABLE MOVE COMPRESS で既存テーブルに圧縮を適用する方法
- DBA_TABLES.COMPRESSION / COMPRESS_FOR で圧縮状態を確認する方法
- DBMS_COMPRESSION.GET_COMPRESSION_RATIO で圧縮率を事前に見積もる方法
基本圧縮と Advanced Row Compression の違い
| 項目 | 基本圧縮(COMPRESS) | Advanced Row Compression |
|---|---|---|
| Oracle 機能名 | Basic Table Compression | Advanced Row Compression(旧: OLTP Table Compression) |
| 構文 | COMPRESS または ROW STORE COMPRESS BASIC |
ROW STORE COMPRESS ADVANCED |
| 圧縮対象の DML | ダイレクトパス INSERT のみ(通常の INSERT/UPDATE は非圧縮) | 通常の INSERT/UPDATE/DELETE もリアルタイムで圧縮 |
| ライセンス | Enterprise Edition に標準搭載 | Advanced Compression オプションが必要 |
| DML パフォーマンスへの影響 | ダイレクトパス以外の DML への影響なし | ごくわずかな CPU オーバーヘッド(通常は許容範囲) |
| 典型的な圧縮率 | 2〜4 倍(データの重複度による) | 2〜4 倍(データの重複度による) |
| 推奨環境 | DWH・バッチ処理(CTAS・INSERT /*+ APPEND */) | OLTP・混在環境 |
圧縮テーブルの作成
CREATE TABLE で圧縮オプションを指定する
-- 基本圧縮(ダイレクトパス INSERT のみ圧縮される)
-- Enterprise Edition 標準機能
CREATE TABLE sales_archive (
order_id NUMBER,
customer_id NUMBER,
product_id NUMBER,
sale_date DATE,
amount NUMBER
)
COMPRESS; -- または ROW STORE COMPRESS BASIC
-- Advanced Row Compression(通常の DML も圧縮される)
-- Advanced Compression オプションが必要
CREATE TABLE orders_oltp (
order_id NUMBER PRIMARY KEY,
customer_id NUMBER NOT NULL,
product_id NUMBER NOT NULL,
order_date DATE DEFAULT SYSDATE,
status VARCHAR2(20),
amount NUMBER
)
ROW STORE COMPRESS ADVANCED;
-- パーティションテーブルでパーティションごとに圧縮を設定する
-- 古いパーティション → 基本圧縮、新しいパーティション → 非圧縮
CREATE TABLE sales_partitioned (
sale_id NUMBER,
sale_date DATE,
amount NUMBER
)
PARTITION BY RANGE (sale_date) (
PARTITION p2022 VALUES LESS THAN (DATE '2023-01-01') COMPRESS, -- 基本圧縮
PARTITION p2023 VALUES LESS THAN (DATE '2024-01-01') COMPRESS, -- 基本圧縮
PARTITION p2024 VALUES LESS THAN (DATE '2025-01-01') NOCOMPRESS -- 圧縮なし(最新データ)
)
NOCOMPRESS; -- テーブルレベルのデフォルトは非圧縮
-- テーブルの圧縮状態を確認する
SELECT table_name, compression, compress_for
FROM DBA_TABLES
WHERE owner = 'HR'
AND table_name IN ('SALES_ARCHIVE', 'ORDERS_OLTP')
ORDER BY table_name;
-- COMPRESSION: ENABLED / DISABLED
-- COMPRESS_FOR: BASIC / ADVANCED / null(DISABLED の場合)
基本圧縮とダイレクトパス INSERT の関係
基本圧縮テーブルでも、通常の INSERT 文では圧縮されません。圧縮を機能させるにはダイレクトパス INSERT(APPEND ヒントや CTAS)が必要です。
基本圧縮テーブルへのデータ挿入パターン
-- 通常の INSERT → 圧縮されない(非圧縮行として格納される) INSERT INTO sales_archive VALUES (1, 100, 200, SYSDATE, 9800); COMMIT; -- ダイレクトパス INSERT(APPEND ヒント)→ 圧縮される INSERT /*+ APPEND */ INTO sales_archive SELECT order_id, customer_id, product_id, order_date, amount FROM orders_staging; COMMIT; -- APPEND ヒントで Direct Path Write が行われ、ブロックに圧縮が適用される -- CTAS(CREATE TABLE AS SELECT)→ 圧縮される CREATE TABLE sales_2023_archive COMPRESS AS SELECT * FROM sales WHERE EXTRACT(YEAR FROM sale_date) = 2023; -- CREATE TABLE ... AS SELECT はダイレクトパスで実行されるため基本圧縮が機能する -- SQL*Loader のダイレクトパス(DIRECT=TRUE)→ 圧縮される -- → sqlldr control=xxx.ctl direct=true -- Advanced Row Compression では通常の INSERT でも圧縮される INSERT INTO orders_oltp VALUES (1001, 100, 200, SYSDATE, 'PENDING', 5000); COMMIT; -- ROW STORE COMPRESS ADVANCED テーブルならこの通常 INSERT でも圧縮が適用される
既存テーブルに圧縮を適用する(ALTER TABLE MOVE)
ALTER TABLE MOVE の注意点
ALTER TABLE MOVE COMPRESS はテーブルの物理的な再作成を伴うため、既存の行インデックスの ROWID がすべて無効になります。MOVE 完了後は必ずすべての関連インデックスを ALTER INDEX ... REBUILD してください。テーブルが大きい場合は ONLINE オプションを使ってロックを最小化することを検討してください。
ALTER TABLE MOVE COMPRESS で既存テーブルを圧縮する
-- 既存テーブルを基本圧縮で再作成する ALTER TABLE hr.sales_archive MOVE COMPRESS; -- Advanced Row Compression で再作成する ALTER TABLE hr.orders_history MOVE ROW STORE COMPRESS ADVANCED; -- ONLINE オプション(Enterprise Edition): DML を許可しながら MOVE する(ロックなし) ALTER TABLE hr.sales_archive MOVE COMPRESS ONLINE; -- MOVE 後はすべてのインデックスが UNUSABLE になるため再構築が必要 -- インデックスの状態を確認する SELECT index_name, status FROM DBA_INDEXES WHERE table_name = 'SALES_ARCHIVE' AND owner = 'HR' ORDER BY index_name; -- STATUS: UNUSABLE になっているインデックスを確認する -- UNUSABLE なインデックスを再構築する ALTER INDEX hr.sales_archive_pk REBUILD ONLINE; ALTER INDEX hr.sales_archive_date_idx REBUILD ONLINE; -- MOVE 後の圧縮状態を確認する SELECT table_name, compression, compress_for, blocks, num_rows FROM DBA_TABLES WHERE owner = 'HR' AND table_name = 'SALES_ARCHIVE'; -- パーティション単位で MOVE して段階的に圧縮を適用する ALTER TABLE hr.sales_partitioned MOVE PARTITION p2022 COMPRESS; ALTER TABLE hr.sales_partitioned MOVE PARTITION p2023 COMPRESS; -- 古いパーティションから順に圧縮することでオンラインサービスへの影響を分散できる
DBMS_COMPRESSION で圧縮率を事前に見積もる
DBMS_COMPRESSION.GET_COMPRESSION_RATIO(Advanced Compression オプションが必要)を使うと、実際に圧縮する前に予想される圧縮率を確認できます。
DBMS_COMPRESSION で圧縮率を見積もる
-- DBMS_COMPRESSION.GET_COMPRESSION_RATIO でサンプルから圧縮率を推定する
DECLARE
v_ratio NUMBER;
v_size_unc NUMBER; -- 非圧縮サイズ(ブロック数)
v_size_comp NUMBER; -- 圧縮後推定サイズ(ブロック数)
v_sample_size NUMBER;
BEGIN
DBMS_COMPRESSION.GET_COMPRESSION_RATIO(
scratchtbsname => 'USERS', -- 作業用一時表領域(十分な空き必要)
ownname => 'HR', -- スキーマ名
tabname => 'SALES_ARCHIVE', -- テーブル名
partname => NULL, -- NULL: テーブル全体 / パーティション名指定可
comptype => DBMS_COMPRESSION.COMP_ADVANCED, -- 圧縮タイプ
blkcnt_cmp => v_size_comp,
blkcnt_uncmp => v_size_unc,
row_cmp => v_ratio,
row_uncmp => v_sample_size,
compress_ratio => v_ratio,
comptype_str => NULL
);
DBMS_OUTPUT.PUT_LINE('推定圧縮率: ' || ROUND(v_ratio, 2) || ' 倍');
DBMS_OUTPUT.PUT_LINE('非圧縮ブロック数: ' || v_size_unc);
DBMS_OUTPUT.PUT_LINE('圧縮後ブロック数: ' || v_size_comp);
END;
/
-- COMP_ADVANCED: Advanced Row Compression
-- COMP_FOR_OLTP: 旧 Oracle 11g の OLTP 圧縮(現在は COMP_ADVANCED を推奨)
-- DBA_TABLES での圧縮確認(統計更新後)
EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'SALES_ARCHIVE');
SELECT
table_name,
compression,
compress_for,
blocks, -- 圧縮後のブロック数
num_rows,
avg_row_len -- 平均行長(バイト)
FROM DBA_TABLES
WHERE owner = 'HR' AND table_name = 'SALES_ARCHIVE';
まとめ
- 基本圧縮(COMPRESS):ダイレクトパス INSERT 時のみ圧縮が適用される。Enterprise Edition に標準搭載。DWH・バッチ一括ロードに向く
- Advanced Row Compression(ROW STORE COMPRESS ADVANCED):通常の INSERT/UPDATE にも対応。Advanced Compression オプションが必要。OLTP 環境でも使える
- ALTER TABLE MOVE COMPRESS:既存テーブルを圧縮形式に再作成する。実行後は必ずインデックスを REBUILD すること
- パーティションへの段階的適用:古いパーティションから順に MOVE することで、大テーブルへの圧縮適用を分散できる
- 圧縮率の目安:データの重複度によるが、一般的に 2〜4 倍のストレージ削減が期待できる
- DBMS_COMPRESSION:Advanced Compression オプションがあれば、実際に圧縮する前に圧縮率を見積もれる
インデックスにも圧縮を適用する方法は インデックス圧縮完全ガイドを参照してください。ダイレクトパス INSERT の詳細と NOLOGGING との組み合わせは ダイレクトパス INSERT 完全ガイドも参照してください。