Partition Projection in AWS Athena

Partition Projection in AWS Athena

Athena Partition Projection, introduced in June 2020, eliminates the need to run MSCK REPAIR TABLE to add new partitions manually.

Takahiro Iwasa
3 min read

Athena Partition Projection, introduced in June 2020, eliminates the need to run MSCK REPAIR TABLE to add new partitions manually.

Building Backend

The key point in the CloudFormation template is the GlueTable.TableInput.Parameters section of the GlueTable definition (lines 27–35). This section enables Partition Projection with the following important properties:

  • projection.enabled: Enables partition projection.
  • projection.year_month.format: Specifies the date format for partitions.
  • projection.year_month.range: Defines the range for partitions, supporting NOW with offsets (e.g., NOW+9HOURS).
💡 Tip

The projection.year_month.range property is treated as UTC. If you intend to use a different timezone, you need to specify the time difference using a format like NOW+9HOURS.

For more details, please refer to the official documentation.

stack.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Stack for Athena partition projection sample
Resources:
S3:
Type: AWS::S3::Bucket
Properties:
BucketName: athena-partition-projection-logs
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
GlueDatabase:
Type: AWS::Glue::Database
Properties:
DatabaseInput:
Name: sample
CatalogId: !Ref AWS::AccountId
GlueTable:
Type: AWS::Glue::Table
Properties:
DatabaseName: !Ref GlueDatabase
CatalogId: !Ref AWS::AccountId
TableInput:
TableType: EXTERNAL_TABLE
Parameters:
classification: json
"projection.enabled": true
"projection.year_month.format": yyyy/MM
"projection.year_month.interval": 1
"projection.year_month.interval.unit": MONTHS
"projection.year_month.range": 2021/09,NOW
"projection.year_month.type": date
"storage.location.template": s3://athena-partition-projection-logs/${year_month}
StorageDescriptor:
Columns:
- Name: id
Type: int
- Name: message
Type: string
Location: !Sub s3://${S3}/
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: false
NumberOfBuckets: 0
SerdeInfo:
SerializationLibrary: org.openx.data.jsonserde.JsonSerDe
Parameters:
paths: id,message
StoredAsSubDirectories: false
PartitionKeys:
- Name: year_month
Type: string
Retention: 0
Name: sample_logs

Deploy the CloudFormation stack:

Terminal window
aws cloudformation deploy \
--template-file stack.yml \
--stack-name athena-partition-projection-sample

Uploading Data

Some test data can then be uploaded to the S3 bucket:

Terminal window
echo '{"id": 1, "message": "hello"}' > 2021-09.json
echo '{"id": 2, "message": "world"}' > 2021-10.json
aws s3 cp 2021-09.json s3://athena-partition-projection-logs/2021/09/
aws s3 cp 2021-10.json s3://athena-partition-projection-logs/2021/10/

Verify that the files are uploaded:

Terminal window
aws s3 ls s3://athena-partition-projection-logs/2021/

Querying Data

Fetching data from the 2021/09 partition confirms the projection works:

SELECT * FROM "sample"."sample_logs"
WHERE year_month = '2021/09'
LIMIT 10;

Expected result:

1 hello 2021/09

The 2021/10 partition behaves the same way:

SELECT * FROM "sample"."sample_logs"
WHERE year_month = '2021/10'
LIMIT 10;

Expected result:

2 world 2021/10

Cleaning Up

Remove the resources provisioned by this example with:

Terminal window
aws s3 rm --recursive s3://athena-partition-projection-logs
aws cloudformation delete-stack --stack-name athena-partition-projection-sample

Conclusion

Deploying a Glue table with partition projection enabled let Athena query newly uploaded year_month partitions immediately, with no MSCK REPAIR TABLE step in between. Setting projection.enabled: true alongside projection.year_month.range: 2021/09,NOW means Athena computes which partitions are valid mathematically, from the range and format, rather than looking them up in the Glue catalog — so there’s no catalog entry to update as each new month’s data lands. That computation depends entirely on the storage.location.template matching the actual S3 key layout, and since NOW is evaluated in UTC, any range meant to track a local calendar month needs an explicit offset like NOW+9HOURS or the projected partitions will drift from the data by however many hours the timezone is off.

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.