[アップデート] Amazon Redshift の Top-K クエリ向けのパフォーマンス最適化を試してみました

[アップデート] Amazon Redshift の Top-K クエリ向けのパフォーマンス最適化を試してみました

2026.04.30

クラウド事業本部の石川です。Amazon Redshift / Amazon Redshift Serverless で ORDER BY 句と LIMIT 句を組み合わせた、いわゆる「Top-K クエリ」の実行が大幅に高速化されるパフォーマンス最適化が導入されました。無関係なデータブロックをインテリジェントにスキップすることで、クエリ実行速度の向上と処理データ量の削減が同時に実現できる、運用に直結するうれしいアップデートです。

https://aws.amazon.com/jp/about-aws/whats-new/2026/04/amazon-redshift-topk-optimization/

Top-K クエリ向けのパフォーマンス最適化とは

今回のアップデートは、ORDER BY 句と LIMIT 句を含む「Top-K クエリ」(上位 K 件を取得するクエリ)の処理を最適化するものです。Amazon Redshift が ORDER BY 列の最小値・最大値(min/max)を活用し、結果に影響しないデータブロックを実行時にスキップすることで、必要最小限のデータのみを処理します。

主な変更点は以下のとおりです。

  • ORDER BY 列の最小値・最大値に基づいて、読み取るデータブロックを並べ替え・調整
  • 上位 K 行に該当する候補行のみをメモリ内に保持
  • ソート済み、または部分的にソート済みの列ではテーブル全体スキャンを回避
  • 不要な I/O とコンピュートオーバーヘッドを削減
  • データが降順で永続的に格納されている場合(例: ORDER BY ... DESC LIMIT K)に特に大きな効果

公式アナウンスでは、「処理データ量を劇的に削減し、結果をより高速に返すことで Top-K クエリのパフォーマンスが大幅に向上する(dramatically reducing the amount of data processed / top-k query performance improves dramatically)」と表現されています。

仕組みのイメージ

たとえば、数億〜数十億件のトランザクションテーブルから「直近の注文 10 件」を取得したいケースを考えてみます。order_date で降順にソートして格納されている場合、従来であれば多くのデータブロックを走査する必要がありました。

今回の最適化では、ORDER BY order_date DESC LIMIT 10 のようなクエリに対して、各データブロックの min/max メタデータから「上位 10 件に入りうるブロック」だけを優先して読み取り、上位 10 件が確定した時点で残りのブロックは読み飛ばす、というイメージで動作します。

利用可能なバージョン

本最適化は、Amazon Redshift のパッチリリース P199 以降で利用可能です。クラスターのメンテナンストラックに従って自動的に適用されます。

なお、パッチリリースノートには次のような記述があります(クラスターバージョンドキュメントより)。

Enhanced query execution performance when using ORDER BY and LIMIT clauses by eliminating unnecessary data scans

Top-K クエリ向けのパフォーマンス最適化を試す

本最適化は、対象となるクエリに対して 自動的に適用 されます。クエリの書き換えや、特別な設定変更は一切必要ありません。

クラスターまたはサーバーレスワークグループが P199 以降のパッチに更新されれば、既存の ORDER BY ... LIMIT K クエリがそのまま高速化の恩恵を受けます。

検証環境

項目
サービス Amazon Redshift Serverless
ワークグループ devio-wg
データベース dev
リージョン ap-northeast-1
スペック 4 RPU
クエリ実行 Redshift Data API(aws redshift-data execute-statement
計測値 describe-statementDuration(ナノ秒)
キャッシュ制御 各実行前に SET enable_result_cache_for_session TO OFF;
計測方針 各クエリを連続 2 回実行(1 回目 = cold, 2 回目 = warm)

検証データ

項目
ソース s3://<bucket_name>/ssbgz/lineorder/
ファイル数 8(GZIP 圧縮 PSV)
圧縮済みサイズ 約 26.9 GB
ロード行数 600,037,902 行
ロード時間 約 644 秒

テーブル定義

CREATE TABLE IF NOT EXISTS "public"."lineorder" (
    "lo_orderkey"        BIGINT       ENCODE AZ64,
    "lo_linenumber"      INTEGER      ENCODE AZ64,
    "lo_custkey"         INTEGER      ENCODE AZ64,
    "lo_partkey"         INTEGER      ENCODE AZ64,
    "lo_suppkey"         INTEGER      ENCODE AZ64,
    "lo_orderdate"       DATE         ENCODE AZ64,
    "lo_orderpriority"   VARCHAR(32)  ENCODE ZSTD,
    "lo_shippriority"    VARCHAR(2)   ENCODE ZSTD,
    "lo_quantity"        INTEGER      ENCODE AZ64,
    "lo_extendedprice"   BIGINT       ENCODE AZ64,
    "lo_ordertotalprice" BIGINT       ENCODE AZ64,
    "lo_discount"        INTEGER      ENCODE AZ64,
    "lo_revenue"         BIGINT       ENCODE AZ64,
    "lo_supplycost"      BIGINT       ENCODE AZ64,
    "lo_tax"             INTEGER      ENCODE AZ64,
    "lo_commitdate"      DATE         ENCODE AZ64,
    "lo_shipmode"        VARCHAR(16)  ENCODE ZSTD
)
DISTSTYLE AUTO
SORTKEY AUTO;

検証クエリ

A. シンプル Top-K(フィルタなし、LIMIT 10

SELECT lo_orderkey, lo_custkey, lo_orderdate, lo_revenue
FROM public.lineorder
ORDER BY lo_revenue DESC
LIMIT 10;

B. フィルタ付き Top-K(1997 年・LIMIT 10

SELECT lo_orderkey, lo_custkey, lo_orderdate, lo_revenue
FROM public.lineorder
WHERE lo_orderdate BETWEEN DATE '1997-01-01' AND DATE '1997-12-31'
ORDER BY lo_revenue DESC
LIMIT 10;

C. GROUP BY + Top-K(顧客別売上 Top-10)

SELECT lo_custkey,
       SUM(lo_revenue) AS total_revenue,
       COUNT(*)        AS orders
FROM public.lineorder
GROUP BY lo_custkey
ORDER BY total_revenue DESC
LIMIT 10;

D. Window 関数 Top-N per group(年別 Top-3)

SELECT yr, lo_orderkey, lo_custkey, lo_revenue
FROM (
  SELECT EXTRACT(YEAR FROM lo_orderdate) AS yr,
         lo_orderkey, lo_custkey, lo_revenue,
         ROW_NUMBER() OVER (PARTITION BY EXTRACT(YEAR FROM lo_orderdate)
                            ORDER BY lo_revenue DESC) AS rn
  FROM public.lineorder
) t
WHERE rn <= 3
ORDER BY yr, rn;

E. K サイズ違い(K = 10 / 10,000 / 1,000,000)

-- K を変えながら同形のクエリを実行
SELECT lo_orderkey, lo_revenue
FROM public.lineorder
ORDER BY lo_revenue DESC
LIMIT <K>;

計測結果

# パターン cold (秒) warm (秒) warm の cold 比
A シンプル Top-K(LIMIT 10 5.382 1.430 約 3.8 倍速
B フィルタ付き Top-K(1997 年・LIMIT 10 1.522 1.292 約 1.2 倍速
C GROUP BY + Top-K(顧客別 Top-10) 17.842 16.293 約 1.1 倍速
D Window 関数 Top-N per group(年別 Top-3) 556.053 564.281 ほぼ同じ
E K=10 6.203 0.903 約 6.9 倍速
E K=10,000 0.783 0.788 ほぼ同じ
E K=1,000,000 468.471 (未計測 / 中断) -

warm 値は同じ SQL を直後にもう 1 回実行したときの計測値。コンパイルキャッシュ+ブロックキャッシュの両方が効いた状態に相当すると考えられる。

K のサイズと実行時間(cold)

K 実行時間 (cold) K=10 比
10 6.203 秒 1.0 倍
10,000 0.783 秒 0.13 倍
1,000,000 468.471 秒 約 75 倍

K=10 と K=10,000 でほぼ同じ時間(むしろ K=10 のほうが遅い: cold ペナルティ)ですが、K=1,000,000 で約 600 倍以上に膨らみ、ある閾値を超えると急激に跳ね上が状態を観察しました。

主要な知見

1. Top-K 最適化(ORDER BY ... LIMIT)は強力

  • 6 億行から上位 10 件を取り出すクエリ(A)が warm 1.4 秒、E_K10 では warm 0.9 秒
  • 各並列スライスで K 件のヒープを保持しマージするだけのため、フルソートを回避

2. K のサイズによる指数関数的増加

  • K=10 → 10,000 :実行時間がほぼ変わらない(むしろ K=10,000 cold は約 0.78 秒)
  • K=10,000 → 1,000,000 :468 秒以上に膨張
  • 各スライスのヒープサイズと最終マージコストが許容量を超えると、Top-K 最適化のメリットが失効する

3. Window 関数 Top-N per group の注意

  • ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)全件にランクを付与してからフィルタ する処理
  • Top-K 最適化の対象外で、6 億行に対しフルソート + PARTITION 処理が走り、約 9 分(556 〜 564 秒)

4. GROUP BY + Top-K のボトルネックは集計

  • C は cold/warm ともに 16〜18 秒
  • ソート/LIMIT は秒未満で、HashAggregate(6 億行を lo_custkey で集約)が支配的
  • DISTKEY を集計キーに合わせると分散シャッフルが減って改善余地がある

5. キャッシュ効果は軽量クエリほど顕著

クエリ cold/warm 比 解釈
A シンプル Top-K 約 3.8 倍 軽量クエリではコンパイルキャッシュの寄与が大きい
E_K10 約 6.9 倍 同上、ブロックキャッシュも効きやすい
C GROUP BY 約 1.1 倍 集計コストが支配的なためほぼ変わらない
D Window 関数 ほぼ同じ フルスキャン + ソートが支配的

軽量で頻繁に実行される Top-K クエリは 2 回目以降の体感値(warm) で評価するのが実態に近い、ということが確認できました。

効果が出やすいユースケース

公式アナウンスで示されている例を含め、以下のような Top-K クエリで特に効果が高くなります。

  • 数百万〜数十億件のトランザクションから 直近 K 件の注文 を抽出する
  • 売上やアクセス数の 上位 K 件の商品・コンテンツ を取得する
  • LLM ワークロードで 直近の K 件のプロンプト をモニタリングする
  • スコアやレイテンシの 上位(または下位)K 件のレコード を抽出する

特に、ORDER BY 対象列がソートキーで降順方向に追記され続けるようなテーブル(時系列ログ、注文履歴など)では、不要なブロックスキャンが大きく削減されるため、効果を体感しやすい構成と言えます。

最後に

当初はあまりにも情報がなくて、なぜ速くなるのがイメージできませんでしたが、様々なクエリの実行を通じて、「無関係なデータブロックをインテリジェントにスキップ」をイメージできるようになりました。

今回のアップデートにより、Amazon Redshift の Top-K クエリは追加料金も クエリ書き換えも不要のまま 、内部最適化だけで実行速度と処理データ量が改善されるようになりました。パッチリリース P199 以降であれば、既存ワークロードがそのまま恩恵を受けられます。

ダッシュボードや BI レポートで ** 「直近の N 件」「上位 N 件」を表示する SQL を多用 ** している環境では、応答時間と消費リソースの両面で効果が見込めます ので、対象パッチへの更新状況を確認してみてはいかがでしょうか。

この記事をシェアする

関連記事