はじめに
AWS環境でログ分析を行う場合、非常によく利用されるサービスが Amazon Athena です。
例えば次のようなログ分析です。
- ALBアクセスログ
- VPC Flow Logs
- CloudFrontアクセスログ
- CloudTrailログ
Athenaを使うと、S3上のログを SQLで直接分析できます。
例)
-- ALB のアクセスログで、ステータスコード 500 のものを10 件表示
SELECT *
FROM alb_logs
WHERE elb_status_code = '500'
LIMIT 10;
サーバを構築する必要がないため非常に便利ですが、
Athenaが内部的にどのようにS3データを分析しているのか、そして、
どのような仕組みで高速にクエリを実行しているのか、ご存じでしょうか。
この記事では、Athenaのアーキテクチャと利用時のベストプラクティス について解説していきます。
Amazon Athenaとは
Amazon Athena は
Amazon S3 をはじめとした "データレイク" に保存されたデータを対象に SQL クエリを実行できるサーバーレス分析サービス
です。
なお、S3以外を対象とすることも可能ですが、今回はS3に絞って解説するため、詳細については割愛します。
S3以外の利用について知りたい方は、以下のドキュメントを参照ください。
特徴
Athenaの主な特徴は以下のとおりです。
- S3等のデータレイクへ直接クエリ
- サーバレス
- スキャンデータ量課金
Athenaのクエリエンジンは
Trino(旧Presto)ベースの分散SQLエンジン
で、TrinoをAWS独自に拡張したものを利用しています。
2026年3月時点では Athena エンジンバージョン 3 が最新バージョンです
AthenaでSQL実行するときの処理フロー
AthenaでSQLを実行するときの処理の流れは以下のとおりです。
大枠としては
- クエリエンジンがSQLを解析
- CoordinatorがWorkerを使って分散処理、S3をスキャン
- 結果保存用S3に実行結果を格納
という流れです
それでは、中身について詳しく解説していきます。
Coordinator と Worker
Athenaは Trino(旧Presto)ベースの分散SQLエンジン を利用していると説明しましたが、
クエリを処理するときに、文字通り、分散処理 を行います。
Trinoは次のような構造でクエリを処理します。
Coordinator
│
├── Worker
├── Worker
└── Worker
Coordinator
Coordinator(コーディネーター) は、クエリ処理の司令塔です。
主に次の処理を担当します。
- SQL解析
- クエリプラン生成
- ステージ管理
- 結果集約
つまり
クエリ全体を管理するコントロールノード
です。
Worker
Worker(ワーカー) は、実際のデータ処理を行うノードです。
担当する処理は
- S3データ読み込み
- フィルタ処理
- 集計処理
つまり
実際に計算を行うノード
です。
次に、Coordinator と Worker の処理の詳細についてみていきます。
Coordinator で行われる処理
Query Plan
Query Plan(実行計画) は、SQLを実行するための 全体設計図 です。
SQLを送ると、Coordinatorが
- どの順序で処理するか
- どこでJOINするか
- どこで集計するか
などを決めます。
例)
SELECT count(*)
FROM alb_logs
WHERE status = 500
これを次のような処理に分解します。
S3読み込み
↓
Filter(status=500)
↓
Aggregation(count)
これが Query Plan です。
Stage
Query Planは、クエリをどのように実行するかを表した実行計画です。
Trinoでは、このQuery Planは複数の Stage で構成されます。
Stageとは、
複数のWorkerノードで並列実行される処理のまとまり
です。
1つのStageはさらに Task に分割され、Workerノードで並列処理されます。
例えば、以下のような構成イメージです
Query Plan(実行計画)
│
├ Stage 1(Scan)
│ ├ Task
│ │ ├ Split
│
├ Stage 2(Filter)
│ ├ Task
│
└ Stage 3(Aggregation)
├ Task
Worker で行われる処理
Task
Stageの処理は Task に分割されてWorkerノード上で処理されます。
例えば
Stage
│
├ Worker1 → Task
├ Worker2 → Task
└ Worker3 → Task
のように、Workerごとに Task が割り当てられます。
Split(最小処理単位)
Split は 実際に読み込むデータの単位 です。
例えばS3にログファイルがある場合
s3://logs/
├ log1
├ log2
└ log3
これをさらに分割して処理します。
Task
├ Split (file1 part1)
├ Split (file1 part2)
├ Split (file2 part1)
Split = データの読み込み単位
で、これらをWorkerが並列処理します。
これらを簡単にまとめると、以下ようなイメージです。
| 概念 | 役割 |
|---|---|
| Query Plan | クエリ全体の処理計画 |
| Stage | 並列処理される処理グループ |
| Task | Worker上の処理 |
| Split | 実際のデータ読み込み単位 |
Athenaのクエリ実行の仕組み
次に、Athenaのクエリがどのように実行され、
どのようにパフォーマンスが最適化されているのかを説明していきます。
Predicate Pushdown(フィルタ最適化)
Athenaでは、可能な限り 早い段階でフィルタ条件を適用する最適化が行われます。
これを Predicate Pushdown と呼びます。
例えば次のクエリを考えます。
SELECT *
FROM alb_logs
WHERE elb_status_code = 500;
単純に考えると処理は次のようになります。
S3からログを読み込む
↓
ステータス500のレコードを抽出
しかしAthenaでは、可能な場合 データ読み込み時点でフィルタ条件を適用 します。
S3 Scan (status=500のみ)
つまり、不要なデータを最初から読み込まないようにすることで、
- スキャン量削減
- クエリ速度向上
- コスト削減
につながります。
特に Parquet や ORC などの列指向フォーマット を利用している場合、
ストレージレイヤーでフィルタ条件が適用されるため、この最適化の効果が大きくなります。
一方で、CSVなどの行指向フォーマットでは、ファイル全体を読み込んでからフィルタが適用されるケースもあるため、
列指向フォーマットのほうがこの最適化の恩恵を受けやすくなります。
Partition Pruning
Athenaの性能に大きく影響するのが パーティションです。
例えば、ALBログを次のように日付をキー名として構成(パーティション分割)しているとします。
s3://logs/alb/
├ day=2026/03/13
├ day=2026/03/14
└ day=2026/03/15
この状態で次のクエリを実行します。
SELECT *
FROM alb_logs
WHERE day = '2026/03/14';
この場合、Athenaは すべてのログをスキャンするのではなく、
day=2026/03/14
のパーティションのみを読み込みます。
この仕組みを Partition Pruning(パーティション削減) と呼びます。
パーティションが適切に設計されている場合、
Athenaのスキャン量は大きく削減されます。
Partition Projection
Athenaでは、パーティションを利用することで
スキャン量を削減できることを説明しました。
通常、Athenaでパーティションを利用する場合、
Glue Data Catalog にパーティション情報を登録する必要があります。
例えば日付パーティションを利用している場合、
day=2026/03/13
day=2026/03/14
day=2026/03/15
のようなパーティションを、ALTER TABLE ADD PARTITION などで登録します。
しかし、ログのように日付単位でデータが増えていく場合、
パーティションを毎日追加する運用は手間になることがあります。
day=2026/03/13
day=2026/03/14
day=2026/03/15
day=2026/03/16 ← 新しい日付のログが追加されていく
day=2026/03/17 ← 新しい日付のログが追加されていく
:
この問題を解決する仕組みが Partition Projection です。
Partition Projectionを利用すると、Athenaがパーティションを
メタデータとして事前登録するのではなく、クエリ実行時に動的に推測
します。
つまり、Glue Data Catalog にすべてのパーティションを登録しなくても、
クエリ条件から必要なパーティションを計算して読み込みます。
例えばAthenaでテーブル定義を作成する際に、次のような設定を行うことで、
Athenaはクエリ条件に応じて、必要なパーティションを動的に生成します。
projection.enabled = true
projection.day.type = date
projection.day.range = 2024/01/01,NOW
| 設定項目 | 説明 |
|---|---|
projection.enabled |
Partition Projectionを有効化する |
projection.day.type |
day パーティションの値の種類(ここでは日付) |
projection.day.range |
Athenaが生成するパーティションの日付範囲(例では、2024/01/01から現在(NOW)まで) |
この仕組みにより
- パーティション追加の運用が不要
- Glueメタデータの肥大化防止
- ログ分析の運用負荷削減
といったメリットがあります。
特に ALBログやCloudTrailログなど、日付単位で増加するログ分析では有効な機能です。
(参考)ALBアクセスログのAthenaテーブル作成例
ALBのアクセスログをAthenaで分析する場合、次のようなテーブル定義を作成します。
CREATE EXTERNAL TABLE alb_logs (
type string,
time string,
elb string,
client_ip_port string,
target_ip_port string,
request_processing_time double,
target_processing_time double,
response_processing_time double,
elb_status_code int,
target_status_code string,
received_bytes bigint,
sent_bytes bigint,
request string,
user_agent string,
ssl_cipher string,
ssl_protocol string,
target_group_arn string,
trace_id string,
domain_name string,
chosen_cert_arn string,
matched_rule_priority string,
request_creation_time string,
actions_executed string,
redirect_url string,
error_reason string,
target_port_list string,
target_status_code_list string
)
PARTITIONED BY (
day string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
'input.regex' = '([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) "([^"]*)" "([^"]*)" ([^ ]*) ([^ ]*) ([^ ]*) "([^"]*)" "([^"]*)" "([^"]*)" ([^ ]*) ([^ ]*) "([^"]*)" "([^"]*)" "([^"]*)"'
)
LOCATION 's3://example-bucket/AWSLogs/ACCOUNT-ID/elasticloadbalancing/REGION/'
TBLPROPERTIES (
'projection.enabled'='true',
'projection.day.type'='date',
'projection.day.range'='2024/01/01,NOW',
'projection.day.format'='yyyy/MM/dd',
'projection.day.interval'='1',
'projection.day.interval.unit'='DAYS',
'storage.location.template'='s3://example-bucket/AWSLogs/ACCOUNT-ID/elasticloadbalancing/REGION/${day}'
);
この設定では、Partition Projectionを利用しているため、
ALTER TABLE ADD PARTITION を実行しなくても日付パーティションが自動的に認識されます。
ALBアクセスログ のデータをクエリするサンプル
以下は、特定の日のALBアクセスログを、HTTPステータスコードごとに集計する クエリです
SELECT elb_status_code, count(*)
FROM alb_logs
WHERE day = '2026/03/14'
GROUP BY elb_status_code
ORDER BY count(*) DESC;
これは、
2026/03/14 の ALBログを対象に
↓
HTTPステータスコードごとに
↓
リクエスト数を集計し
↓
多い順に並べる
ということをやっています。
Splitによる並列処理
Athenaは Split という単位でデータを並列処理することを説明しましたが
S3にログファイルが複数存在する場合、
AthenaはこれらをSplit単位に分割し、複数のWorkerノードで並列処理します。
そのため、例えば
1TBの1ファイル
より
100MB × 10000ファイル
のほうが並列度が上がります。
この仕組みにより、Athenaは 大量のデータを高速に処理することができます。
列指向フォーマット
Athenaでは Parquet や ORC などの列指向フォーマットが推奨されています。
一般的なCSVなどのログは 行指向フォーマットです。
time,method,status,bytes
10:00,GET,200,512
10:01,POST,500,128
上記のようなCSV形式で、例えば次のクエリを実行するとします。
SELECT status
FROM alb_logs;
この場合、CSVでは
time
method
status
bytes
すべての列を読み込む必要があります。
一方、Parquetのような 列指向フォーマットでは、データは列単位で保存されています。
time
method
status
bytes
そのため、上記のデータをクエリすると
status列のみ
を読み込むことができます。
Athenaは スキャンしたデータ量に応じて課金されるため、
列指向フォーマットを利用することで
- スキャン量の削減
- クエリ速度の向上
- コスト削減
といった効果が得られます。
EXPLAINでクエリプランを確認する
Athenaでは、EXPLAIN を利用することで、クエリの実行計画(Query Plan) を確認できます。
これにより、クエリがどのように実行されるかを把握することができます。
例えば、次のようなクエリを考えます。
SELECT elb_status_code, count(*)
FROM alb_logs
WHERE day = '2026/03/14'
GROUP BY elb_status_code;
このクエリの実行計画を確認するには、クエリの先頭に EXPLAIN を付けて実行します。
EXPLAIN
SELECT elb_status_code, count(*)
FROM alb_logs
WHERE day = '2026/03/14'
GROUP BY elb_status_code;
するとAthenaは、実際にクエリを実行する代わりに、
以下のような クエリプラン(実行計画) を表示します。
Fragment 1
Output layout: [elb_status_code, count]
Aggregate
group by: elb_status_code
Scan
Table: alb_logs
Filter: day = '2026/03/14'
ここで表示される Fragment は、Trinoの内部実行単位であり、
概念的には Stage(並列実行される処理のまとまり) に対応します。
つまり
Fragment ≒ Stage
と考えると理解しやすいです。
実行計画の読み方としては、下から上に読むことで処理の流れを理解できます。
一番下 = データ取得
↓
途中 = データ処理
↓
一番上 = 出力
今回の例では、処理の流れは次のようになります。
S3データスキャン
↓
day = '2026/03/14' のフィルタ
↓
ステータスコードごとの集計
↓
出力
となっていることがわかります。
このように EXPLAIN を利用することで、
- クエリの実行順序
- フィルタの適用位置
- 集計処理の流れ
などを確認することができます。
特に、Athenaでは パーティション条件が適切に利用されているか を確認する際にも有効です。
また、EXPLAIN ANALYZE を使うと、実際にクエリを実行しながら、次のような統計情報を確認することができます。
- CPU使用時間
- 入力された行数
- 出力された行数
- 各処理の実行時間
これにより、クエリのボトルネックを把握することができます。
詳細については以下のドキュメントを参照してください。
Athenaのクエリ結果
Athenaの特徴のひとつとして、クエリ結果が S3に保存される点があります。
クエリを実行すると、結果は指定された Query Result Location に保存されます。
Athena
↓
Query Result
↓
S3 Result Location
この仕組みにより、Athenaはデータベースサーバを持たずに
サーバーレスなクエリエンジンとして動作します。
なお、この仕組みを実務上で活用できる点としては以下の点があげられます
| 活用ポイント | 内容 | 実務での例 |
|---|---|---|
| 結果の共有 | クエリ結果がS3に保存されるため、URLやファイルとして共有できる | Excelで確認、BIツール連携、チームへの共有 |
| 中間データの作成 | 分析結果をS3に保存することで、後続クエリの入力データとして再利用できる | 日次アクセス集計、エラーログ集計 |
| ETL処理の一部として利用 | AthenaのSQLでデータを整形し、その結果をS3に保存できる | ログ → 集計データ → BI用データセット |
| 自動処理との連携 | S3に保存された結果をトリガーに他の処理を起動できる | S3イベント → Lambda → 通知 |
| クエリ結果の再利用 | 重いクエリの結果をS3に保存しておき、後続分析に使える | 大規模ログ分析のキャッシュ |
| データレイク連携 | 保存された結果を他の分析基盤から再利用できる | Glue / Spark / Redshift Spectrum |
クエリ課金
Athenaのクエリを実行したときの課金の考え方としては、
スキャンデータ量課金
です。
$5 / TB
そのため、さきほど説明した、
- Partition
- 列指向フォーマット
- Predicate Pushdown
を活用して スキャン量削減 することが、パフォーマンスのみならず コスト削減 にもつながります
Athenaでのベストプラクティス
Athenaは、S3上のログをSQLで分析できる非常に便利なサービスですが、
ログの保存方法やクエリの書き方によって、クエリ性能やコストが大きく変わります。
先ほどご紹介したAthenaのクエリの仕組みも踏まえて、あらためて
Athenaでのベストプラクティス(推奨事項)をまとめてみました。
小さすぎるファイルを避ける
Athenaでは ファイルサイズがパフォーマンスに影響します。
ログが次のように非常に小さいファイルとして保存されている場合、
1KB × 100万ファイル
Athenaはそれぞれのファイルを個別に読み込む必要があるため、
クエリ性能が低下する可能性があります。
一般的には、次のようなサイズが推奨されます。
100MB〜1GB程度
- 小さすぎる: Worker効率悪い
- 大きすぎる: 並列度低い
不要な列を取得しない
Athenaでは、必要な列だけを取得することでスキャン量を減らすことができます。
例えば、次のクエリを比較してみます。
SELECT *
FROM alb_logs;
SELECT elb_status_code, time
FROM alb_logs;
前者ではすべての列を読み込みますが、
後者では必要な列のみを読み込みます。
特に列数の多いログでは、この違いがスキャン量に大きく影響します。
パーティションを活用する
パーティションを適切に設計することで、
Athenaのスキャン量を大幅に削減することができます。
すでに内容については記載済みですので、ここではパーティションが活用可能な
AWSサービスに関して紹介しておきます。
Athenaでパーティションを活用する際、AWSサービスログは大きく次の2つに分類できます。
- 出力されたログをそのまま使える(AWSが日付パスを自動生成)
- パーティション構造を自分で設計・設定する必要がある
そのままAthenaでパーティション活用できるログ
これらは S3保存時に日付ディレクトリが自動生成されるため、ログの移動や再構成は不要です。
Athena側でテーブル定義を作るだけで利用できます。
| サービス | S3保存パス例 |
|---|---|
| ALB / ELB Access Logs | AWSLogs/account/elasticloadbalancing/region/yyyy/mm/dd |
| CloudTrail | AWSLogs/account/CloudTrail/region/yyyy/mm/dd |
| VPC Flow Logs | AWSLogs/account/vpcflowlogs/region/yyyy/mm/dd |
| Route53 Resolver Query Logs | AWSLogs/account/route53resolver/region/yyyy/mm/dd |
| AWS Network Firewall Logs | AWSLogs/account/network-firewall/region/yyyy/mm/dd |
| CloudFront Access Logs | distribution-id/YYYY-MM-DD-HH |
パーティション設計を自分で行う必要があるログ
次のログは S3には保存されるものの、パーティション設計はユーザー側で行うケースが多いです。
| サービス | 理由 |
|---|---|
| AWS WAF Logs | Kinesis Data Firehose経由でS3保存され、prefix設計はユーザー側 |
| CloudWatch Logs Export | エクスポート時のパスがフラット |
| SES Logs | 保存方法によっては日付パーティションにならない |
| アプリケーションログ | 当然ながら自前設計 |
| Firehose配信ログ | S3 prefixをユーザーが決定 |
この場合、次のような構造を自分で設計するのが一般的です。
s3://logs/app/
year=2026/
month=03/
day=14/
列指向フォーマットを利用する
こちらも基本的な内容は前述で記載済みのため
ここでは実務で参考になる、「どう作るか」の観点で補足していきます。
Parquetに関する推奨事項
Parquet変換のメリット
Parquet形式に変換することで、次のようなメリットがあります。
| 項目 | 効果 |
|---|---|
| 列指向フォーマット | 必要な列だけ読み込める |
| 圧縮 | データサイズ削減 |
| スキャン量削減 | Athenaコスト削減 |
| クエリ速度向上 | 分析の高速化 |
例えば、CSV形式のログが1TBある場合でも、
CSV 1TB
↓
Parquet
↓
100〜300GB
程度までデータ量が削減されることがあります。
Athenaは スキャンしたデータ量に応じて課金されるため、
Parquet形式を利用することはコスト削減にもつながります。
Parquet形式へ変換する方法
既存のCSVやJSON形式のログデータは、Athenaの CTAS(CREATE TABLE AS SELECT) を利用することで、簡単にParquet形式へ変換することができます。
例えば、次のようなテーブルがあるとします。
SELECT *
FROM alb_logs
LIMIT 10;
このテーブルはCSV形式のログデータを参照しているとします。
このデータをParquet形式に変換するには、次のようなクエリを実行します。
CREATE TABLE alb_logs_parquet
WITH (
format = 'PARQUET',
external_location = 's3://example-bucket/alb-logs-parquet/'
)
AS
SELECT *
FROM alb_logs;
このクエリを実行すると、
- 元の alb_logs テーブルからデータを読み込み
- Parquet形式に変換し
- 指定したS3パスに保存
という処理が行われます。
元データ(CSV)
↓
Athena CTAS
↓
Parquetデータ
↓
S3保存
生成されたParquetデータは、そのままAthenaのテーブルとして利用することができます。
適切なファイルサイズ
行指向(CSVなど)か列指向(Parquetなど)かに関わらず、前述のような 推奨ファイルサイズ(100MB〜1GB) で作成することが重要です
圧縮
Parquetは
- Snappy
- ZSTD
などの圧縮が利用可能です。
例
CSV 1TB
↓
Parquet + Snappy
↓
100〜200GB
つまり
スキャン量が減る → Athenaコスト削減
ということにつながります。
クエリ結果を再利用する
Athenaのクエリ結果は S3に保存されるため、分析結果を再利用することができます。
例えば、ログを直接分析するのではなく、1日ごとのアクセス数を事前に集計したテーブルを作成しておくことで、
Rawログ
↓
Athena集計
↓
集計データ
のように、後続の分析を高速化することができます。
このようにAthenaを 簡易的なETL処理として活用することも可能です。
まとめ
この記事では、Amazon Athenaの内部アーキテクチャとクエリ実行の仕組みについて解説しました。
Athenaは Trino(旧Presto)ベースの分散SQLエンジン であり、
- Coordinator がクエリ全体を管理
- Worker がデータ処理を分散実行
- Query Plan → Stage → Task → Split という構造で並列処理
という仕組みで、大量のS3データを高速に分析しています。
また、Athenaのパフォーマンスとコストを最適化するためには、
- Predicate Pushdown
- Partition Pruning
- Partition Projection
- 列指向フォーマット(Parquet / ORC)
といった仕組みを理解し、適切に活用することが重要です。
Athenaはサーバーレスで非常に手軽に利用できる一方で、
データ配置やクエリ設計によって性能が大きく変わるサービスでもあります。
本記事を、Athenaを利用したログ分析やデータ分析を行う際の参考していただけると幸いです。