【Oracle】近似クエリ(Approximate Query Processing)完全ガイド|APPROX_COUNT_DISTINCT・APPROX_PERCENTILE で大規模データを高速集計する

数億件規模のテーブルで COUNT(DISTINCT)PERCENTILE_DISC を実行すると、非常に時間がかかることがあります。近似クエリ(Approximate Query Processing)は、厳密な正確値ではなく「誤差の保証された近似値」を超高速で返します。

Oracle 12.2 以降で提供される APPROX_COUNT_DISTINCTAPPROX_PERCENTILE などの近似集計関数は、確率的データ構造(HyperLogLog・T-Digest など)を使って数秒以内に信頼性の高い近似値を返せます。リアルタイムダッシュボード・大規模ログ分析・探索的データ分析(EDA)で活躍します。

この記事でわかること

  • 近似クエリが必要な場面と正確クエリとの使い分け
  • APPROX_COUNT_DISTINCT で高速なカーディナリティ推定を行う方法
  • APPROX_COUNT_DISTINCT_DETAIL / AGG でブロック単位の事前集計を活用する方法
  • APPROX_PERCENTILE でパーセンタイル値を高速計算する方法
  • APPROX_MEDIAN・APPROX_SUM・APPROX_COUNT(Oracle 19c 以降)の使い方
  • 誤差率の考え方と近似クエリが許容できるユースケース
スポンサーリンク

近似クエリと正確クエリの比較

関数(正確) 関数(近似) 導入バージョン 誤差の目安
COUNT(DISTINCT col) APPROX_COUNT_DISTINCT(col) Oracle 12.2 ほぼ 0〜2 %(データ量に依存)
PERCENTILE_DISC(0.5) WITHIN GROUP APPROX_PERCENTILE(0.5) Oracle 12.2 百分位ランク誤差 0.5 % 以内
MEDIAN(col) APPROX_MEDIAN(col) Oracle 19c APPROX_PERCENTILE(0.5) と同等
SUM(col) APPROX_SUM(col) Oracle 19c APPROX_RANK 使用時の補助関数
COUNT(*) APPROX_COUNT(col) Oracle 19c APPROX_RANK 使用時の補助関数

APPROX_COUNT_DISTINCT でカーディナリティを高速推定する

APPROX_COUNT_DISTINCT の基本的な使い方
-- APPROX_COUNT_DISTINCT: COUNT(DISTINCT) の近似値を返す
-- 大規模テーブルで COUNT(DISTINCT) より大幅に速い

-- 正確な COUNT(DISTINCT)(大規模テーブルでは重い)
SELECT COUNT(DISTINCT customer_id) AS exact_count
FROM orders;

-- 近似 COUNT(DISTINCT)(同等の結果をはるかに速く返す)
SELECT APPROX_COUNT_DISTINCT(customer_id) AS approx_count
FROM orders;
-- 数億件でも数秒以内に結果を返すことが多い

-- GROUP BY との組み合わせ
SELECT
    product_category,
    COUNT(*) AS order_count,
    APPROX_COUNT_DISTINCT(customer_id) AS unique_customers,
    APPROX_COUNT_DISTINCT(product_id)  AS unique_products
FROM orders
WHERE order_date >= DATE '2024-01-01'
GROUP BY product_category
ORDER BY unique_customers DESC;

-- 月別のユニークユーザー数を集計する(ダッシュボード向け)
SELECT
    TRUNC(order_date, 'MM')           AS month,
    APPROX_COUNT_DISTINCT(customer_id) AS monthly_unique_customers
FROM orders
GROUP BY TRUNC(order_date, 'MM')
ORDER BY month;
APPROX_COUNT_DISTINCT_DETAIL と APPROX_COUNT_DISTINCT_AGG
Oracle 12.2 以降では APPROX_COUNT_DISTINCT_DETAIL でブロック単位の中間集計をBLOB として格納しておき、後から APPROX_COUNT_DISTINCT_AGG で再集計できます。毎日の集計結果を保存しておき、月次・年次の APPROX_COUNT_DISTINCT を生データに戻らずに計算するマテリアライズドビュー的な活用が可能です。
APPROX_COUNT_DISTINCT_DETAIL で事前集計して高速再集計する
-- ステップ 1: 日次サマリーテーブルに中間集計(スケッチ)を格納する
CREATE TABLE daily_customer_sketch AS
SELECT
    TRUNC(order_date, 'DD')               AS order_day,
    product_category,
    APPROX_COUNT_DISTINCT_DETAIL(customer_id) AS cust_sketch   -- BLOB として格納
FROM orders
GROUP BY TRUNC(order_date, 'DD'), product_category;

-- ステップ 2: スケッチから月次・週次を再集計する(生データへの再スキャン不要)
SELECT
    TRUNC(order_day, 'MM')                   AS month,
    product_category,
    APPROX_COUNT_DISTINCT_AGG(cust_sketch)    AS monthly_unique_customers
FROM daily_customer_sketch
GROUP BY TRUNC(order_day, 'MM'), product_category
ORDER BY month, product_category;
-- 生データに戻らずに月次集計が可能 → 大幅な高速化

APPROX_PERCENTILE でパーセンタイル値を高速計算する

APPROX_PERCENTILEPERCENTILE_DISC の近似版です。大量のデータに対してパーセンタイル値(中央値・95パーセンタイルなど)を高速に計算できます。

APPROX_PERCENTILE の使い方
-- APPROX_PERCENTILE: パーセンタイル値の近似値を返す
-- 構文: APPROX_PERCENTILE(percentile_value) WITHIN GROUP (ORDER BY col)

-- 中央値(50パーセンタイル)を取得する
SELECT
    department_id,
    APPROX_PERCENTILE(0.5) WITHIN GROUP (ORDER BY salary) AS median_salary,
    APPROX_PERCENTILE(0.9) WITHIN GROUP (ORDER BY salary) AS p90_salary,
    APPROX_PERCENTILE(0.99) WITHIN GROUP (ORDER BY salary) AS p99_salary
FROM employees
GROUP BY department_id
ORDER BY department_id;

-- 正確な PERCENTILE_DISC との比較
SELECT
    APPROX_PERCENTILE(0.5)  WITHIN GROUP (ORDER BY salary) AS approx_median,
    PERCENTILE_DISC(0.5)    WITHIN GROUP (ORDER BY salary) AS exact_median,
    APPROX_PERCENTILE(0.95) WITHIN GROUP (ORDER BY salary) AS approx_p95,
    PERCENTILE_CONT(0.95)   WITHIN GROUP (ORDER BY salary) AS exact_p95
FROM employees;
-- 大規模データでは APPROX_PERCENTILE が大幅に速い

-- APPROX_MEDIAN(Oracle 19c 以降): APPROX_PERCENTILE(0.5) と同等
-- SELECT APPROX_MEDIAN(salary) FROM employees GROUP BY department_id;

-- DET パラメータ: 誤差限界を指定する(デフォルト: 'ERROR_RATE '0.5'')
SELECT
    APPROX_PERCENTILE(0.95, 'ERROR_RATE 0.1')
        WITHIN GROUP (ORDER BY response_time_ms) AS p95_fast
FROM web_request_logs
WHERE request_date >= DATE '2024-01-01';
-- ERROR_RATE: パーセンタイルランクの最大誤差(0.1 = 0.1 % 以内)
-- 誤差を小さくするほど処理時間がかかる(デフォルトの 0.5 が通常は十分)

近似クエリを使うべき場面・使わない場面

近似クエリが適した場面

  • リアルタイムダッシュボード:数秒以内のレスポンスが必要でわずかな誤差が許容できる
  • 探索的データ分析(EDA):傾向をざっくり把握したい段階(後で正確値を取得)
  • ログ・トラッキングデータ:数億件以上のアクセスログ・イベントデータのカーディナリティ
  • パーセンタイルの傾向確認:レスポンスタイムの P95・P99 の推移確認(厳密値不要)
近似クエリを使ってはいけない場面

  • 請求・会計処理:金額の合計・カウントは厳密な値が必要(APPROX_SUM は不向き)
  • コンプライアンスレポート:監査目的のレポートには正確値が必要
  • 小規模データ:数万件程度では COUNT(DISTINCT) も速く、近似の意味がない
  • ロジックの分岐条件:「ユーザー数が 1000 人以上かどうか」で処理を分ける場合は正確値を使う

まとめ

  • APPROX_COUNT_DISTINCT:Oracle 12.2 以降。COUNT(DISTINCT) の近似版。大規模データでのユニーク数集計が大幅に速い
  • APPROX_COUNT_DISTINCT_DETAIL / AGG:中間集計(スケッチ)を BLOB で保存して後から再集計できる。マテリアライズドビュー的な活用が可能
  • APPROX_PERCENTILE:PERCENTILE_DISC/CONT の近似版。GROUP BY との組み合わせで中央値・P95・P99 を高速計算できる
  • APPROX_MEDIAN:Oracle 19c 以降。APPROX_PERCENTILE(0.5) と同等のシンタックスシュガー
  • 誤差保証:APPROX_COUNT_DISTINCT はほぼ 2 % 以内。APPROX_PERCENTILE はランク誤差 0.5 % 以内がデフォルト
  • 使い分け:ダッシュボード・EDA・大規模ログ分析には近似クエリ。請求・監査・ロジック分岐には正確クエリを使う

大規模データの集計パフォーマンス改善には、インメモリ列ストア(Oracle In-Memory)も有効です。Oracle In-Memory 完全ガイドを参照してください。マテリアライズドビューで集計結果を事前計算する方法は マテリアライズドビュー完全ガイドも参照してください。