はじめに
AWSのBig Data Blogに How to use Parquet Column Indexes with Amazon Athena という記事が上がっていたので読んでみた。ParquetのPageIndex機能をAthenaで使うことでクエリが速くなり、スキャン量が削減できる、という内容だ。
ただ、記事はあくまで「どう設定するか」の説明がメインで、「どういうときに使うべきか」「逆に使っても意味がないケースはどこか」は特に書かれていない。こういうクエリ効率化は使いどころしくじると全く役に立たないどころか害悪になりうるので調べてみた。
この記事はその学習メモとなる。
【結論】 フランクに有効化してもほぼ恩恵を受けられない。「クエリ速度・コストがクリティカルな場面で、ちゃんと設計したうえで使う最後の一手」 という位置づけである。
(前提)Parquetファイルの構造
Parquetは列指向の圧縮フォーマットで、データは以下の3階層で管理されている。
| 階層 | 単位 | 典型サイズ | 典型レコード数 |
|---|---|---|---|
| File | Parquetファイル全体 | 数百MB〜数GB | 数百万〜数千万行 |
| Row Group | ファイル内のかたまり | 128MB〜512MB | 数十万〜数百万行 |
| Page | 列内の最小単位 | 〜1MB | 数千〜数万行 |
Footer と呼ばれるメタデータ領域に、各 Row Group の Min/Max 統計が保持される。Athena はクエリ実行時にまずこの Footer を読み、対象の Row Group のみを絞り込む。
ファイル構造イメージ

(https://parquet.apache.org/docs/file-format/ より参照)
1. Column Indexesがない場合の問題
従来の Athena は Row Group レベルの統計しか保持していなかったため、以下のような非効率が発生する。
問題のシナリオ
cs_item_sk = 2 を絞り込むクエリを実行した場合:
Row Group全体: min=1, max=20 → 範囲内なので全Pageを読む
Page-0: min=1, max=10 → 該当しうる → 読む
Page-1: min=1, max=10 → 該当しうる → 読む
Page-2: min=5, max=15 → 2は含まれない → 本来スキップできる
Page-3: min=6, max=16 → 2は含まれない → 本来スキップできる
Page-4: min=10, max=20 → 2は含まれない → 本来スキップできる
Row Group 内に1つでも対象値を含む可能性のある Page が存在すると、Athena はその Row Group 内の全 Page をスキャンする(無駄なスキャンが積み上がる)。
Athena の課金はスキャン量に比例するため、この非効率は直接コスト増に繋がる。
2. Column Indexesによる改善
Parquet Column Indexes機能 は、Page レベルの Min/Max 統計を Footer に追加で保持する仕組みです。これにより Athena はより精密なデータの枝刈り(Pruning)が可能になります。
改善後の動作
Row Group全体: min=1, max=20 → 引き続きスキャン対象
Page Indexを参照:
Page-0: min=1, max=10 → 2が入りうる → 読む ✅
Page-1: min=1, max=10 → 2が入りうる → 読む ✅
Page-2: min=5, max=15 → 2は含まれない → スキップ ⏭
Page-3: min=6, max=16 → 2は含まれない → スキップ ⏭
Page-4: min=10, max=20 → 2は含まれない → スキップ ⏭
2種類のインデックス
| インデックス | 役割 |
|---|---|
| Column Index | 各 Page の Min/Max 値を保持。「この Page に対象データがあるか」の判断に使う |
| Offset Index | 各 Page のファイル内バイト位置を保持。スキップしたい Page を物理的に飛ばすための「住所」として使う |
AWSブログでの実測値(3TB TPC-DSデータセット)
| 条件 | 実行時間 | スキャン量 |
|---|---|---|
| ソートなし・Column Indexなし(ベースライン) | 20.6秒 | 45.2 GB |
| ソートあり・Column Indexなし | 15.4秒(▲25%) | 27.8 GB(▲38%) |
| ソートあり・Column Indexあり | 10.3秒(▲50%) | 13.0 GB(▲71%) |
3. Column Indexesを設定する際の注意点
3-1. ソートが前提条件
ここまでの説明で分かる通り、Column Indexes はデータがソートされていないとほぼ効果がない(ソートされていない状態では各 Page の Min/Max 範囲が広く重複するため、スキップしにくいため)。
ソート前(効果なし)
page-0: min=4, max=359989 ← ほぼ全範囲をカバー
page-1: min=2, max=359996 ← ほぼ全範囲をカバー
page-2: min=10, max=359995 ← ほぼ全範囲をカバー
→ どのページにも任意の値が存在しうる → スキップ不可
ソート後(効果あり)
page-0: min=1, max=5282 ← 非重複で明確に分離
page-1: min=5282, max=10556
page-2: min=10556, max=15842
→ 値の範囲が重複せず → 大半のPageをスキップ可能
3-2. 有効化は手動設定が必要(S3汎用バケットの場合)
| テーブル種別 | デフォルト動作 | 有効化方法 |
|---|---|---|
| S3 Tables | 自動で使用される | 設定不要 |
| S3汎用バケット上のIceberg | 使用されない | Glue テーブルプロパティの設定が必要 |
3-3. ソートキーは実質1カラム
複数カラムでのソートは技術的に可能だが、Column Indexes の恩恵を受けられるのは第1ソートキーに限られる。第2キー以降は第1キーが同じ範囲内でしか整列されないため、Page 単位ではランダムに近い状態が続く(「どのカラムを第1ソートキーにするか」という一択の設計判断になる)。
3-4. パーティションキーとの重複は無意味
パーティションキーに設定したカラムでフィルターした場合、Athena はファイルレベルで絞り込みを行う。そのカラムを Column Indexes のソートキーにしても、そもそも対象外のファイルが読まれないため効果はほぼゼロになる。
3-5. ソートキーのメンテナンスが必要
ソートキーを活用するときはいつでもそうだが、新データが入るたびにソートの状態が崩れるので定期的に再ソートする運用が必要になる。「有効化した=改善した」にはならず、微小ながら運用保守のコストを継続的に払い続ける必要がある。
4. 実務的な使用判断
効果が出る条件
- テーブルが数GB以上ある(小さいテーブルはフルスキャンでも普通に速い)
- 高カーディナリティなカラムでフィルターする要件がある(
user_id、item_idなど、値の種類が多いカラム) - そのカラムがソートされており、かつパーティションキーではない
3段階の絞り込みと役割分担
Athena のデータ絞り込みには3段階あり、それぞれが担う役割が異なる。パーティションと Column Indexes は重複させず、直交する軸で設計する。
| 段階 | 技術 | スキップ単位 | 設計の指針 |
|---|---|---|---|
| ① | パーティション | ファイル単位 | 日付・地域など時系列・カテゴリ軸 |
| ② | Row Group Min/Max 統計 | Row Group 単位 | 自動(設定不要) |
| ③ | Column Indexes + ソート | Page 単位 | 高カーディナリティな ID カラム等 |
設計例
eコマース注文データを例に、典型的な設計を示す。
テーブル:orders
パーティション → sold_date(日付)
日次バッチで頻繁に絞るため
Column Indexソートキー → item_id(商品ID)
高カーディナリティ
パーティションと直交する軸
「この商品の売上は?」系クエリが多い
WHERE sold_date = '2024-03-15' AND item_id IN (...) というクエリに対して、①でファイルを絞り、③でPage内をさらに絞る2段階が機能する。
まとめ
Parquet Column Indexes、確かに便利だが、正直に言うと重箱の隅をつつく感じは否めない。
ソートが前提なので、新データが入るたびに状態が崩れるので定期的に再実行する運用も必要になる。「有効化した=改善した」にはならず、設計・実施・保守のコストを継続的に払い続ける必要がある。
より優先すべき最適化(パーティション設計・ファイルサイズの適正化・Parquet化)を一通りやり切っているのが大前提で、それでもなおクエリ速度・コストをもう一段改善したい、という強い要望があるときに初めて手を出す選択肢というのが率直な印象かなぁ。
「とりあえず入れておく」の類のものではない、というのが結論。
参考:How to use Parquet Column Indexes with Amazon Athena | AWS Big Data Blog(2026年4月13日)