Oracle 12c から導入された In-Memory Column Store(IM 列ストア)は、テーブルデータを SGA 内の専用領域にカラム指向フォーマットで保持することで、集計・範囲スキャン・フィルタリングを大幅に高速化する機能です。
通常のバッファキャッシュが行指向(ROW 形式)でデータを保持するのに対して、IM 列ストアは列指向(COLUMN 形式)で保持します。SELECT COUNT・GROUP BY・WHERE による集計クエリでは列単位で読み込むため、不要列のスキャンを省略でき、圧縮効率も高くなります。
この記事でわかること
- In-Memory Column Store の仕組みとバッファキャッシュとの違い
- INMEMORY_SIZE パラメータで IM 領域を有効化する方法
- テーブル・列・パーティションに INMEMORY 句を設定する方法
- MEMCOMPRESS オプションで圧縮方式を選択する方法
- V$IM_SEGMENTS でロード状況を確認・管理する方法
- 分析クエリで効果的に活用するポイント
In-Memory 列ストアの仕組み
| 項目 | バッファキャッシュ(従来) | In-Memory 列ストア |
|---|---|---|
| データ形式 | 行指向(ROW: 1ブロック = 複数行) | 列指向(COLUMN: 1単位 = 1列の連続データ) |
| 得意なクエリ | 主キー検索・小規模結果の OLTP | 大量行スキャン・集計・範囲検索(分析系) |
| 圧縮 | ブロック圧縮(オプション) | 列指向圧縮(辞書圧縮・RLE など自動適用) |
| SGA 内の場所 | Buffer Cache | In-Memory Area(IM 領域) |
| 両立 | バッファキャッシュと IM 列ストアは同時に使用できる(DML は両方を更新) | |
IMCUとは
IM 列ストア内のデータは IMCU(In-Memory Compression Unit)という単位で管理されます。1 IMCU には特定の列の行範囲(通常 64K ~ 128K 行)が圧縮格納され、クエリのフィルタリングは IMCU 内のメタデータ(最大値・最小値など)を使って不要 IMCU を高速にスキップします。
IM 列ストア内のデータは IMCU(In-Memory Compression Unit)という単位で管理されます。1 IMCU には特定の列の行範囲(通常 64K ~ 128K 行)が圧縮格納され、クエリのフィルタリングは IMCU 内のメタデータ(最大値・最小値など)を使って不要 IMCU を高速にスキップします。
INMEMORY_SIZE で IM 領域を有効にする
INMEMORY_SIZE パラメータを確認・設定する
-- 現在の設定を確認する
SHOW PARAMETER inmemory_size;
-- デフォルト: 0(無効)
-- IM 領域を有効化する(SPFILE に保存し再起動が必要な静的パラメータ)
ALTER SYSTEM SET inmemory_size = 4G SCOPE=SPFILE;
-- 設定後、Oracle インスタンスを再起動する
SHUTDOWN IMMEDIATE;
STARTUP;
-- 有効化後の確認
SELECT pool, alloc_bytes/1024/1024/1024 AS alloc_gb,
used_bytes/1024/1024/1024 AS used_gb,
populate_status
FROM V$INMEMORY_AREA;
-- populate_status: COMPLETE(全テーブルロード完了)/ POPULATING(ロード中)
-- In-Memory を全体で有効にするパラメータの確認
SHOW PARAMETER inmemory_force;
-- DEFAULT(デフォルト): テーブル設定に従う
-- OFF: IM を無効にする(テスト・無効化用)
テーブル・列・パーティションに INMEMORY 句を設定する
テーブルに INMEMORY 句を設定する(CREATE TABLE / ALTER TABLE)
-- CREATE TABLE 時に INMEMORY を指定する
CREATE TABLE sales_fact (
sale_id NUMBER,
sale_date DATE,
product_id NUMBER,
customer_id NUMBER,
amount NUMBER(12,2),
quantity NUMBER
)
INMEMORY; -- デフォルト: MEMCOMPRESS FOR QUERY LOW(クエリ優先の軽圧縮)
-- 既存テーブルを IM 対象に追加する
ALTER TABLE sales_fact INMEMORY;
-- 圧縮レベルを指定して設定する
ALTER TABLE sales_fact INMEMORY MEMCOMPRESS FOR QUERY HIGH;
-- MEMCOMPRESS のオプション:
-- FOR QUERY LOW : 軽圧縮、クエリ速度優先(デフォルト)
-- FOR QUERY HIGH : 高圧縮、クエリ速度も高速(推奨バランス)
-- FOR CAPACITY LOW : スペース効率優先(クエリ速度は低下)
-- FOR CAPACITY HIGH: 最高圧縮率
-- NO MEMCOMPRESS : 圧縮なし(最速アクセスだがメモリ消費が大きい)
特定の列だけ INMEMORY 対象にする(列単位の制御)
-- 分析で使う列のみ IM 対象にし、大きなテキスト列は除外する
ALTER TABLE sales_fact
INMEMORY MEMCOMPRESS FOR QUERY HIGH
(sale_date, product_id, customer_id, amount, quantity) -- IM 対象の列
NO INMEMORY (sale_id); -- 主キーなど IM 不要な列は除外
-- パーティション表では特定パーティションだけ IM 対象にできる
ALTER TABLE sales_fact
MODIFY PARTITION sales_2024
INMEMORY MEMCOMPRESS FOR QUERY HIGH;
-- 古いパーティションは IM から除外する(スペース節約)
ALTER TABLE sales_fact
MODIFY PARTITION sales_2020
NO INMEMORY;
V$IM_SEGMENTS でロード状況を確認する
V$IM_SEGMENTS で In-Memory へのロード状況を確認する
-- IM 列ストアにロードされているセグメントの一覧
SELECT
owner,
segment_name,
partition_name,
populate_status, -- COMPLETE(完了)/ POPULATING(ロード中)/ OUT OF MEMORY(メモリ不足)
inmemory_size / 1024 / 1024 AS im_size_mb, -- IM 内での使用サイズ
bytes / 1024 / 1024 AS disk_size_mb, -- ディスク上のサイズ
ROUND(bytes / NULLIF(inmemory_size, 0), 1) AS compress_ratio -- 圧縮率
FROM V$IM_SEGMENTS
ORDER BY owner, segment_name;
-- ロード状況のサマリを確認する(テーブル単位)
SELECT
owner,
segment_name,
populate_status,
inmemory_size / 1024 / 1024 AS im_mb
FROM V$IM_SEGMENTS
WHERE populate_status != 'COMPLETE' -- まだロードが完了していないものを確認
ORDER BY segment_name;
テーブルを IM に手動でロード・解放する
-- テーブルの IM ロードを手動でトリガーする(デフォルトは最初のアクセス時に遅延ロード)
-- Oracle 12.2 以降: DBMS_INMEMORY を使って即時ロードできる
BEGIN
DBMS_INMEMORY.POPULATE(
schema_name => 'SALES',
table_name => 'SALES_FACT'
);
END;
/
-- テーブルを IM から解放して IM 領域を回収する(物理データは削除しない)
BEGIN
DBMS_INMEMORY.UNPOPULATE(
schema_name => 'SALES',
table_name => 'SALES_FACT'
);
END;
/
-- DBA_TABLES で INMEMORY 設定を確認する(INMEMORY 列)
SELECT table_name, inmemory, inmemory_compression, inmemory_priority
FROM DBA_TABLES
WHERE owner = 'SALES'
ORDER BY table_name;
分析クエリでの効果を確認する
実行計画で In-Memory が使われているか確認する
-- EXPLAIN PLAN で実行計画を確認する
EXPLAIN PLAN FOR
SELECT product_id, SUM(amount), COUNT(*)
FROM sales_fact
WHERE sale_date >= DATE '2024-01-01'
GROUP BY product_id;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => 'TYPICAL'));
-- TABLE ACCESS INMEMORY FULL が表示されれば IM 列ストアを使用中
-- TABLE ACCESS FULL のみ → 通常のバッファキャッシュ(IM 未使用)
-- V$SQL でクエリの IM 使用を確認する
SELECT sql_id, executions,
im_scans, -- IM スキャン回数
im_scan_bytes_uncompressed, -- スキャンされた非圧縮データ量
SUBSTR(sql_text, 1, 80)
FROM V$SQL
WHERE im_scans > 0 -- IM を使用したクエリのみ
ORDER BY executions DESC;
In-Memory Column Store の使いどころ
| 効果が高い場面 | 効果が低い場面 |
|---|---|
| 大量行フルスキャン + 集計(SUM・COUNT・AVG) | 主キー検索(インデックスの方が高速) |
| GROUP BY や HAVING による集計クエリ | OLTP の短い DML トランザクション |
| Wide テーブルの一部列のみ参照するクエリ | 全列を SELECT する行単位アクセス |
| 日付範囲・数値範囲のフィルタリング | テキスト検索(LIKE %keyword%) |
| BI・データウェアハウス的なワークロード | IM 領域に収まらないほど大きなテーブル |
In-Memory Column Store の注意点
- INMEMORY_SIZE は静的パラメータのため変更に再起動が必要(SGA_TARGET の自動調整対象外)
- DML 更新は IM 内のデータも更新されるが、未コミットの変更は IMCU にジャーナル(WCU)として保持される
- 再起動後は IM 領域が空になり、最初のアクセス時に再ロードされる(SAVE STATE は利用できない)
- Enterprise Edition が必要(Standard Edition では使用不可)
まとめ
- INMEMORY_SIZE:IM 領域のサイズを設定する静的パラメータ(再起動が必要)
- INMEMORY 句:テーブル・列・パーティション単位で IM 対象を細かく制御できる
- MEMCOMPRESS FOR QUERY HIGH:バランスの良い圧縮設定(クエリ速度と圧縮率を両立)
- V$IM_SEGMENTS:ロード状況・使用サイズ・圧縮率をリアルタイムで確認できる
- TABLE ACCESS INMEMORY FULL:実行計画で In-Memory が使われているか確認する指標
- 分析クエリの大量行スキャン・集計に効果的。OLTP の主キー検索にはインデックスが依然として有効
SGA・バッファキャッシュ全体のメモリ設計は SGA・PGAメモリ管理完全ガイドを参照してください。実行計画の詳細確認は DBMS_XPLAN完全ガイドも活用してください。