Based on the DEA-C01 exam guideReport an error
key=value) partitions are pruned by the partition keys in the WHERE clause. Match the keys to the filters of the most common queries, and do not slice finely for rare queries.The core of a data lake is "leave the original data untouched, and build up refined copies stage by stage." There are three reasons S3 sits at the bottom of it.
💡 Related Theory: A data lake is schema-on-read, while a data warehouse is schema-on-write. A lake stores structured, semi-structured, and unstructured data in its original form and assigns a schema at query time. Ingestion is therefore fast and flexible, but quality validation is pushed back until after ingestion. This is where the reason for splitting zones comes from.
Separate buckets or prefixes by processing stage. A three-tier layout is typical, and it is the same concept as bronze/silver/gold in the medallion architecture.
s3://company-datalake-raw/ # Raw(Bronze) — original as-is, immutable
└── source=salesforce/dt=2026-06-25/...
s3://company-datalake-clean/ # Clean(Silver) — validated, deduplicated, type-normalized
└── domain=sales/orders/year=2026/month=06/day=25/...
s3://company-datalake-curated/ # Curated(Gold) — business aggregates, consumed by BI/ML
└── mart=revenue/daily_summary/year=2026/month=06/...| Zone | Holds | Format | Written by | Read by | Principle |
|---|---|---|---|---|---|
| Raw | Collected originals as-is | Source format (JSON, CSV, logs) | Ingestion pipeline | Data engineers, ETL | Never overwrite. The single source of truth for reprocessing |
| Clean | Data with validated schema, handled missing values, normalized types | Parquet/ORC | Glue ETL, Spark | ETL, some analysts | Keeps the per-source structure, the stage before joins |
| Curated | Analytics-ready data after joins and aggregation | Parquet/ORC or a table format | Aggregation jobs | Athena, QuickSight, ML | Partitioning and sorting tailored to consumption patterns |
Partitioning is a technique that splits data into per-key prefixes to reduce the amount a query scans.
s3://datalake-clean/orders/year=2026/month=06/day=25/region=us-east-1/file.parquetThe key=value form is called Hive-style partitioning, and the Glue crawler and Athena's MSCK REPAIR TABLE recognize this form as partitions.
-- Partition pruning works: only the year/month/day prefix is scanned
SELECT region, SUM(amount)
FROM orders
WHERE year = 2026 AND month = 6 AND day = 25
GROUP BY region;Athena processes this query in the following order.
GetPartitions on the Glue Data Catalog to get the partition list.Three facts follow from this order.
-- Check which partitions will be read before running
EXPLAIN SELECT COUNT(*) FROM orders WHERE dt BETWEEN '2026-06-23' AND '2026-06-25';
-- If [[2026-06-23], [2026-06-24], [2026-06-25]] appears under the dt:string:PARTITION_KEY line of the output, pruning succeededyear=/month=/day= hierarchy or as a single dt=2026-06-25 key. A single key makes range conditions easier to write and keeps projection settings simpler.| Choice | What you gain | What you lose |
|---|---|---|
| No partitioning | Nothing to manage | Every query is a full scan |
| Date (daily) | Scan volume for date queries drops sharply, easy to manage | Filters on other axes still scan everything |
| Date + region etc., 2 to 3 levels | Pruning on both axes | Partition count = product of each key's value count, files get fragmented |
| Hourly or high cardinality | Only very narrow queries are fast | Small file explosion, catalog and listing overhead |
The small files problem: When planning a query, Athena lists the locations of all target partitions and pays request and processing overhead for each file. For the same records, one large file is faster than several small files. S3 listing returns at most 1,000 entries at a time, so if a partition has more than 1,000 files, listing takes multiple calls. With columnar formats, small files let the format's own overhead outweigh its benefits (the default Parquet row group size is 128MB).
The best time is before writing. If they have already piled up, merge them.
| Situation | Action |
|---|---|
| Streaming ingestion pours out small files | Increase the writer-side buffer (Firehose buffer size and interval) |
| Partitions are split too finely | Reduce the partition keys |
| A Glue job is slow reading hundreds of thousands of small JSON/CSV files | Group them at read time with groupFiles/groupSize |
| Small Parquet files already accumulated | Rewrite and merge with a Glue/Spark job or Athena CTAS |
| Iceberg table | OPTIMIZE ... REWRITE DATA USING BIN_PACK or Glue automatic compaction |
groupFiles is an option that groups multiple files into one task at read time. It applies to formats such as csv, json, and xml, and is not supported for Parquet, ORC, or Avro input. Glue turns it on automatically when there are more than 50,000 input files. Making output files larger is a separate matter, and requires reducing the number of partitions before writing.# Glue: read small JSON files grouped into roughly 128MB units
dyf = glueContext.create_dynamic_frame.from_options(
"s3",
{"paths": ["s3://acme-datalake-raw-prod/events/"], "recurse": True,
"groupFiles": "inPartition", "groupSize": "134217728"},
format="json",
)| Method | Behavior | Suitable when | Caveats |
|---|---|---|---|
MSCK REPAIR TABLE | Scans S3 and adds Hive-style partitions to the catalog | When first creating a table, or when consistency is in doubt | Only adds, never deletes. Slow with many partitions, and on timeout only some are registered |
ALTER TABLE ADD PARTITION | Registers only the specified partitions | Pipelines that create a new partition every day, non-Hive-style paths | The pipeline must call it directly |
| Glue crawler | Detects and registers the schema and partitions | Sources whose schema changes along with them | Delayed by the run interval. Crawler run cost |
| Partition projection | Computes from rules in table properties without registration | Very many partitions with a regular pattern | Works only in Athena |
key=value, such as 2026/06/25/, MSCK REPAIR TABLE cannot find it. Specify the location directly with ALTER TABLE ADD PARTITION ... LOCATION, or use the path template of projection.ALTER TABLE DROP PARTITION. Empty partitions are also listed at the planning stage, so they slow things down when they pile up.When GetPartitions calls are the bottleneck for a table with many partitions, you can have Athena skip the catalog and compute partition values and locations in memory from rules written in the table properties.
ALTER TABLE orders SET TBLPROPERTIES (
'projection.enabled' = 'true',
'projection.dt.type' = 'date',
'projection.dt.range' = '2024-01-01,NOW',
'projection.dt.format' = 'yyyy-MM-dd',
'storage.location.template' = 's3://datalake-clean/orders/dt=${dt}/'
);NOW, so the partition registration task disappears.injected type (which takes the value from an equality condition in the query) instead of a range.⚠️ Pitfall: Pruning and projection are different things. Pruning means "read only the partitions that match the condition," and it always happens on a partitioned table. Projection means "compute the partition list instead of fetching it from the catalog." If the correct answer is "reduce scan volume," it is pruning; if the correct answer is "remove the burden of catalog lookups and partition registration," it is projection.
acme-datalake-raw-prod.domain/entity/partition order. Give each table a non-overlapping path. If another table's path lies under one table's path, MSCK REPAIR TABLE pulls in the other table's partitions too.userId= may not be registered by MSCK REPAIR TABLE.orders_20260625_a1b2.parquet.S3 handles at least 3,500 PUT/COPY/POST/DELETE requests and 5,500 GET/HEAD requests per second per prefix, with no limit on the number of prefixes. So hashed prefixes for request distribution are no longer required, and a meaningful hierarchy takes priority. However, this scaling is gradual, so 503 Slow Down can occur while requests spike. If an Athena query fails with SlowDown, there are too many files or concurrent queries are piling onto the same data.
| Aspect | CSV/JSON (row-based) | Parquet/ORC (columnar) |
|---|---|---|
| Range read | Whole rows | Only the needed columns |
| Skipping | Not possible | Skips ranges outside the condition using per-range min/max statistics |
| Compression efficiency | Low | High, because values of the same type sit together |
| Split parallel processing | Mostly impossible when compressed | Possible regardless of compression codec |
| Suitable zone | Raw | Clean, Curated |
# Example of loading Parquet into the Clean zone (AWS CLI)
aws s3 cp ./orders.parquet \
s3://acme-datalake-clean-prod/sales/orders/year=2026/month=06/day=25/orders.parquet| Symptom | Cause | Action |
|---|---|---|
| Files exist in S3 but the result is 0 rows | Partition not registered | ALTER TABLE ADD PARTITION, a crawler, or projection |
| Only a specific date gives 0 rows on a projection table | Out of range or path template mismatch | Check projection.*.range and storage.location.template |
| A date was given in WHERE but scan volume is unchanged | The condition is on a regular column, not a partition key | Filter by the partition key, verify with EXPLAIN |
| The query planning phase is long | Tens of thousands of partitions, accumulated empty partitions | Projection or partition index, clean up old partition metadata |
SlowDown error | Too many small files, concentrated concurrent queries | Merge files, reduce partition keys, spread out queries |
MSCK REPAIR TABLE cannot find partitions | Not Hive-style, or the path contains uppercase | ALTER TABLE ADD PARTITION ... LOCATION |
| Storage cost and request cost rise together | Small file explosion | Increase writer-side buffer, compaction |
| Clue in the question | Answer |
|---|---|
| "Keep the original unchanged, the baseline for reprocessing" | Raw zone |
| "Queries only a specific date but scans everything" | Partition by date, then filter by the partition key |
| "Tens of thousands of partitions, catalog lookups are slow / automate partition registration" | Partition projection |
| "The same table is read by both Athena and Redshift Spectrum" | Register partitions in the catalog (projection alone is not enough) |
| "Hundreds of thousands of small files make queries slow" | Compaction, write large files on the producer side |
| "Read only the needed columns to cut cost" | Parquet/ORC |
| "Most queries look up a specific user_id" | Bucketing, not partitioning |
| "Add one new partition every day" | ALTER TABLE ADD PARTITION or projection (repeatedly running MSCK is inefficient) |
Tomorrow we cover Lake Formation, which centrally controls "who can see which tables, columns, and rows" on top of this lake.
key=value in the path.Click a choice to reveal the answer and explanation.
Question 1
Which zone in a data lake keeps the ingested raw data without ever modifying it and serves as the single source of truth for reprocessing?
Question 2
Which technique makes the condition WHERE year=2026 AND month=6 in an Athena query scan only the corresponding prefix?
Question 3
What is the most appropriate problem that occurs when files in a data lake are split into tens of thousands of very small files?
Question 4
Which Athena feature reduces catalog bottlenecks by computing partitions from rules in the table properties instead of registering partitions in the Glue Data Catalog?
Question 5
In an analytical data lake, which recommended file format reads only the needed data by column to reduce the amount scanned and has high compression efficiency?