CUR(Cost and Usage Report)を Athena でクエリしていて、スキャン量が思ったより多くてびっくりした。 調べてたら、Glue ETL で事前に集計しておくと劇的にデータ量を削減できるとわかったのでまとめておく。
CUR の生データがどれだけ大きいか
CUR を Hourly + リソース別で設定している場合、「1リソース × 1時間 × 1課金タイプ = 1行」になる。
EC2 を例にとると、50 インスタンス × 3 課金タイプ(インスタンス時間・EBS・データ転送など)× 24 時間 × 30 日 = 108,000 行、これだけで EC2 だけの数字だ。
さらに CUR にはカラムが 200 列以上あって、タグや製品属性など大半のクエリで使わないカラムが大量に含まれている。 実際に試してみたら 1 ヶ月分の CUR が 430MB になっていた。
Glue で事前集計するとどうなるか
account_id・service_code・タグの 3 カラムだけ残して SUM(cost) でまとめると、430MB が 42KB まで圧縮できた。
SELECT line_item_usage_account_id AS account_id, product_servicecode AS service_code, resource_tags_user_env AS tag_env, SUM(line_item_unblended_cost) AS total_cost FROM cur_raw WHERE bill_billing_period_start_date = '2026-02-01' GROUP BY 1, 2, 3
圧縮が効く理由は 2 つあって、行の集約(数百万行 → 数百行)とカラム削減(200 列以上 → 3〜5 列)が同時に起きる。
パイプライン全体像
CUR(S3 raw)
└─ Glue Crawler → Glue ETL(GROUP BY)→ S3 aggregated
└─ Athena → QuickSight
生データは S3 Glacier にアーカイブしておいて、詳細分析が必要なときに復元(Restore)してから使う。Glacier からの復元には数分〜数時間かかるので、緊急時のドリルダウンが必要なら Standard のまま残すか S3 Intelligent-Tiering を検討するのもあり。 日次ダッシュボードは集計済みデータだけ見るようにすれば十分だった。
Athena のスキャン課金への効果
Athena の料金は $5/TB なので、430MB のファイルをクエリすると 1 クエリあたり $0.002 になる。 1 回あたりは安く見えるが、ダッシュボードが定期的にクエリを投げると積み重なる。
集計済みの 42KB ファイルに対してクエリすれば、コストはほぼ $0 になる。
CUR 2.0 でも根本解決にはならない
CUR 2.0(Data Exports)ではカラム選択に加えて TIME_GRANULARITY を DAILY / MONTHLY に変更できるようになった。リソース別の出力を外すこともできるので、行数もある程度は減らせる。
ただし、タグ軸での自由な集計や複雑な GROUP BY(たとえばタグ × サービス × 期間の組み合わせ)は CUR 2.0 の設定だけでは対応しきれない。そこは Glue ETL の出番になる。
Glue のコストはどの程度か
Glue ETL の料金は DPU 数 × 実行時間で決まる。 月次の CUR 集計ジョブであれば数セントから数十セントの範囲に収まることが多い。
Athena でのスキャン削減額のほうがほぼ確実に上回るので、費用対効果は出やすい。
注意点
生データを削除してしまうと、タグ別の詳細なコスト分析や異常値のドリルダウンができなくなる。 集計済みデータはダッシュボード用、生データはデバッグ・監査用と役割を分けて両方残しておくのがよかった。
また、集計の粒度(GROUP BY するカラム)はユースケースに合わせて決める必要がある。 「月次コスト合計を見たいだけ」と「タグ別・日別のトレンドを見たい」では集計キーが変わってくる。
まとめ
- CUR の生データは行×カラム両方の爆発で大きくなりやすい
- Glue ETL で GROUP BY + SUM すると 430MB → 42KB 程度まで圧縮できた
- Athena のスキャン課金対策としてはかなり効果的で、Glue の実行コストは十分回収できる
- 生データは Glacier に退避しておくと詳細分析が必要になったときに対応できる