【Oracle】In-Memory Column Store完全ガイド|INMEMORY句・IM領域の設定・V$IM_SEGMENTS・分析クエリ高速化まで解説

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 を高速にスキップします。

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完全ガイドも活用してください。