透過 AWS Athena 查詢 DynamoDB 資料
前言
DynamoDB 是 AWS 上的 NoSQL 資料庫,雖然效能優異,但在進行複雜查詢時相當受限。如果想對 DynamoDB 的資料做 SQL 查詢、跨表格 JOIN 或聚合分析,原生 API 很難做到。
AWS Athena 的 Federated Query(聯合查詢) 功能正好解決這個問題,透過 Lambda Connector 作為橋接層,讓 Athena 可以用 SQL 直接查詢 DynamoDB 的資料,而不需要先把資料 ETL 到別的地方。
這篇筆記記錄如何用 Terraform 把這整套架構部署起來。
架構概覽
使用者送出 SQL 查詢
│
▼
┌───────────────────────────────┐
│ Athena Workgroup │ ← 執行 SQL,結果存到 S3
└──────────────┬────────────────┘
│
▼
┌───────────────────────────────┐
│ Athena Data Catalog │ ← FEDERATED 類型,橋接 DynamoDB
│ (dynamodb-connector-catalog) │
└──────────────┬────────────────┘
│
▼
┌───────────────────────────────┐
│ Lambda Connector │ ← 由 SAR 部署,實際呼叫 DynamoDB API
│ (AthenaDynamoDBConnector) │
└──────────────┬────────────────┘
│
┌───────┴────────┐
▼ ▼
DynamoDB Tables S3 Spill Bucket
(原始資料來源) (溢出暫存,超過 Lambda 記憶體時使用)
整個流程如下:
- 使用者對 Athena Workgroup 送出 SQL 查詢
- Athena 辨識出這是 Federated Catalog,呼叫對應的 Lambda Connector
- Lambda Connector 呼叫 DynamoDB API 取得資料
- 若資料量超過 Lambda 記憶體上限,多餘的資料會先溢出到 Spill S3 Bucket
- 查詢結果回傳給 Athena,最終寫入 Query Results S3 Bucket
- 使用者可從 Athena Console 或 API 取得結果
元件說明
| 元件 | 名稱 | 用途 |
|---|---|---|
| S3 Bucket | athena-dynamodb-connector-spill-bucket-* | Connector Lambda 的溢出暫存桶 |
| S3 Bucket | athena-query-results-* | Athena 查詢結果存放處 |
| CloudFormation Stack | athena-dynamodb-connector | 透過 SAR 部署 Lambda Connector |
| Lambda Function | 由 SAR Stack 建立 | 實際執行 DynamoDB 查詢的核心元件 |
| Athena Data Catalog | dynamodb-connector-catalog | FEDERATED 類型的資料目錄 |
| Glue Catalog Database | dynamodb_database | DynamoDB 表格的 schema metadata 管理 |
| Athena Workgroup | dynamodb-workgroup | 執行查詢的工作群組,指定結果輸出位置 |
Terraform 程式碼說明
1. Provider 設定
provider "aws" {
region = "us-west-2"
default_tags {
tags = {
Environment = "Test"
Owner = "Allen Chiang"
Project = "QueryDynamoDBWithAthena"
}
}
}
透過 default_tags 統一幫所有資源打上標籤,方便成本管理與資源識別。
2. S3 Spill Bucket
resource "random_string" "spill_bucket_suffix" {
length = 4
upper = false
special = false
numeric = false
}
resource "aws_s3_bucket" "athena_dynamodb_connector_spill_bucket" {
bucket = "athena-dynamodb-connector-spill-bucket-${random_string.spill_bucket_suffix.result}"
}
S3 Bucket 名稱必須全球唯一,因此用 random_string 加上後綴避免命名衝突。
Spill Bucket 是 Athena Federated Query 的必要元件:當 Lambda Connector 處理的資料量超過其記憶體限制時,多餘的資料會先溢出到這個 bucket,Athena 再從這裡讀取合併。預設情況下溢出資料使用 AES-GCM 加密,也可以指定 KMS Key 進一步管理金鑰。
3. 部署 AthenaDynamoDBConnector
data "aws_serverlessapplicationrepository_application" "athena_dynamodb_connector" {
application_id = "arn:aws:serverlessrepo:us-east-1:292517598671:applications/AthenaDynamoDBConnector"
}
resource "aws_serverlessapplicationrepository_cloudformation_stack" "athena_dynamodb_connector" {
name = "athena-dynamodb-connector"
application_id = data.aws_serverlessapplicationrepository_application.athena_dynamodb_connector.application_id
semantic_version = data.aws_serverlessapplicationrepository_application.athena_dynamodb_connector.semantic_version
capabilities = data.aws_serverlessapplicationrepository_application.athena_dynamodb_connector.required_capabilities
parameters = {
AthenaCatalogName = "dynamodb-connector-catalog"
SpillBucket = aws_s3_bucket.athena_dynamodb_connector_spill_bucket.bucket
}
}
AWS 在 Serverless Application Repository(SAR)上提供了官方的 AthenaDynamoDBConnector。這裡用 data source 取得最新版本資訊,再透過 CloudFormation Stack 部署。
AthenaCatalogName:指定 Connector 對應的 Athena Data Catalog 名稱,必須與後面建立的 Catalog 同名,且只能使用小寫SpillBucket:指定溢出資料的暫存 bucketcapabilities:CloudFormation Stack 需要CAPABILITY_IAM和CAPABILITY_RESOURCE_POLICY才能建立 IAM Role 和資源策略
若選擇手動從 SAR Console 部署,步驟如下:
- 進入 Serverless Application Repository → Available applications
- 勾選「Show apps that create custom IAM roles or resource policies」
- 搜尋
AthenaDynamoDBConnector並選擇 - 填入
AthenaCatalogName和SpillBucket等參數 - 勾選 IAM 確認並點擊 Deploy
4. Athena Data Catalog(Lambda)
resource "aws_athena_data_catalog" "dynamodb" {
depends_on = [aws_serverlessapplicationrepository_cloudformation_stack.athena_dynamodb_connector]
name = "dynamodb-connector-catalog"
description = "Athena data source for querying DynamoDB via federated query"
type = "LAMBDA"
parameters = {
function = "arn:aws:lambda:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:function:dynamodb-connector-catalog"
}
}
這是整個架構的核心:建立一個 LAMBDA 類型的 Athena Data Catalog。
type = "LAMBDA"告訴 Athena 這個 Catalog 要透過 Lambda Connector 存取外部資料來源name必須與 CloudFormation Stack 中的AthenaCatalogName相同depends_on確保 Lambda Connector 先部署完成才建立 Catalog- Data Catalog 名稱不可使用保留字:
awsdatacatalog、hive、jmx、system
6. Query Results Bucket 與 Workgroup
resource "aws_s3_bucket" "athena_query_results" {
bucket = "athena-query-results-${random_string.spill_bucket_suffix.result}"
}
resource "aws_athena_workgroup" "dynamodb" {
name = "dynamodb-workgroup"
configuration {
result_configuration {
output_location = "s3://${aws_s3_bucket.athena_query_results.bucket}/results/"
}
}
}
Athena Workgroup 是執行查詢的邏輯單位,可以控制查詢的輸出位置、掃描資料量上限等設定。這裡指定查詢結果存到專用的 S3 Bucket。
IAM 權限需求
Connector Lambda 的 IAM Role 由 SAR CloudFormation Stack 自動建立,底層需要以下權限:
| 服務 | 權限 | 用途 |
|---|---|---|
| S3 | Write | 將溢出資料寫入 Spill Bucket |
| Athena | GetQueryExecution | 偵測上游查詢是否已終止,快速失敗 |
| Glue Data Catalog | Read-only | 讀取 Table schema metadata |
| DynamoDB | DescribeTable, ListSchemas, ListTables, Query, Scan | 執行實際查詢 |
| CloudWatch Logs | Write | 記錄 Lambda 執行日誌 |
部署步驟
terraform init
terraform plan
terraform apply
部署完成後,AWS 上會建立好所有元件,可以開始使用 Athena 查詢 DynamoDB。
如何使用
基本查詢
在 Athena Console 選擇 dynamodb-workgroup workgroup,查詢時需同時指定 federated catalog、database 和 table:
SELECT *
FROM "dynamodb-connector-catalog"."default"."my_table"
LIMIT 100;
功能限制
使用 AthenaDynamoDBConnector 時需注意以下限制:
- 不支援寫入操作:
INSERT INTO、UPDATE、DELETE均不支援,僅能執行SELECT - 欄位大小寫:若搭配 Lake Formation 使用,只能識別全小寫的 table 和 column 名稱
- 不支援 Multiplexing:使用 Glue Connections 方式部署時不支援 multiplexing handler
- Sort Key 多條件過濾:需要 v2023.11.1 以上版本才能在同一 sort key 欄位上使用多個過濾條件
效能注意事項
- Hash Key 查詢:若
WHERE條件包含 Partition Key 的多個明確值,Connector 會對每個值發出一次 DynamoDBQuery呼叫,效率較高 - 其他條件:使用非 Key 欄位過濾時,底層為
Scan操作,會掃描整張表,RCU 消耗高 - 選取欄位:
SELECT *不一定比SELECT col1, col2快,在某些情況下選取部分欄位反而會增加執行時間,建議實際測試後決定 - LIMIT 下推:
LIMIT子句會被下推到 DynamoDB 層,可有效減少不必要的資料讀取
費用考量
這個架構會產生以下費用:
- Athena 查詢費用:每次查詢依掃描的資料量計費($5 / TB)
- Lambda 執行費用:每次查詢都會觸發 Lambda Connector
- S3 儲存與請求費用:Spill Bucket 和 Query Results Bucket 的存取費用
- DynamoDB 讀取費用:Scan 操作會消耗大量 RCU,對 Provisioned Throughput 表格影響尤其顯著
對於 production 環境,建議:
- 設定 Athena Workgroup 的
bytes_scanned_cutoff_per_query限制單次查詢掃描量上限 - 定期清理 Spill Bucket 和 Query Results Bucket 中的舊資料
- 評估是否需要定期將 DynamoDB 資料匯出到 S3 + Glue,改用 Athena 直接查 Parquet,對高頻查詢場景成本更低
小結
透過 Athena Federated Query + AthenaDynamoDBConnector,可以用熟悉的 SQL 語法查詢 DynamoDB,適合以下場景:
- 臨時性的資料探索與分析
- 跨 DynamoDB 表格的聯合查詢
- 搭配 Glue 其他資料來源做跨系統 JOIN
- 快速驗證資料內容,不需建立額外的 ETL pipeline
整個架構用 Terraform 管理,部署、版本控制、重現都很方便。