Amazon Athena

AWS Athena 101: serverless SQL on S3 explained

Amazon Athena is a serverless SQL engine that reads files in S3 through table definitions in the AWS Glue Data Catalog. There is nothing to provision, and a query costs $5 per terabyte it scans. Partitions and columnar formats decide how much that is, so table design is cost design.

Amazon AthenaIevgen Krasovytskyi8 min read

AWS Athena 101: serverless SQL on S3 explained

Amazon Athena lets you run SQL on files that sit in Amazon S3. There is no cluster to start and no data to load: you describe the files as a table, write a query, and pay for the data that query reads.

That one sentence hides the two things that decide whether Athena works for you. The table definition tells Athena where the files are and how to read them, and the price is per terabyte scanned, so the way files are laid out decides what every query costs. This guide walks through both with SQL you can adapt.

What Athena is, in three parts

What Athena is, in three parts

Athena is easier to reason about as three separate pieces that happen to be used together.

  • Amazon S3 holds the data. CSV, JSON, Parquet or ORC files under a bucket prefix. Athena never copies them.
  • The AWS Glue Data Catalog holds the table definitions. A table is metadata: column names and types, the file format, and the S3 location. Dropping a table removes the definition, not the files.
  • Athena is the engine. It takes a SQL statement, looks up the table in the catalog, reads the matching files from S3 and returns the result. Its SQL dialect is Trino’s.

Because the engine and the storage are separate, the same files can be queried by other tools, and the same engine can be pointed at new files by adding a table. What Athena does not have is anything that stays warm: no always-on compute, no indexes, no cache you size.

What a query costs

What a query costs

Athena’s default pricing is by data scanned. On the Athena pricing page, checked in October 2026, SQL queries cost $5 per terabyte scanned, rounded up to the nearest megabyte, with a 10 MB minimum per query.

Three things follow from that.

A query that reads less costs less. Scanning one day of a table instead of three years is the difference between cents and dollars, for the same answer.

Small queries are not free. The 10 MB minimum means a dashboard that fires thousands of tiny queries a day still adds up.

The result does not set the price. LIMIT 10 on an unpartitioned text table can still read the whole table to find ten rows.

You also pay standard S3 rates for storage and requests, and Data Catalog rates for the metadata. For steady, heavy workloads AWS sells provisioned capacity at $0.30 per DPU-hour as an alternative to per-scan pricing.

The Turning Point

OWOX Data Marts

See your first report built in real time. 15 minutes.

  1. Connect your data warehouse
  2. Pick your metrics
  3. Get a live Google Sheets report

In the time it takes to write a ticket. Then imagine never writing that ticket again.

Book a Demo

We'll use your actual use case

Create a table over files in S3

Create a table over files in S3

Suppose order events land in S3 as Parquet files, one folder per day:

s3://my-bucket/orders/dt=2026-09-29/part-000.parquet
s3://my-bucket/orders/dt=2026-09-30/part-000.parquet

The dt=... folder names are Hive-style partitions. This DDL makes them a table:

CREATE EXTERNAL TABLE orders (
  order_id string,
  customer_id string,
  product_id string,
  quantity int,
  price double
)
PARTITIONED BY (dt string)
STORED AS PARQUET
LOCATION 's3://my-bucket/orders/';

EXTERNAL means Athena does not own the files. PARTITIONED BY declares dt as a column that comes from the folder name, not from inside the files.

Tell Athena which partitions exist

A partitioned table returns nothing until its partitions are registered. For Hive-style folders, one statement finds them:

MSCK REPAIR TABLE orders;

It has to be run again whenever new folders arrive. If your paths are not in key=value form, add each partition yourself with ALTER TABLE orders ADD PARTITION (dt = '2026-09-30') LOCATION '...'.

For tables that gain a partition every day, partition projection removes that chore. You describe the pattern once in the table properties and Athena works out the partitions at query time:

ALTER TABLE orders SET TBLPROPERTIES (
  'projection.enabled' = 'true',
  'projection.dt.type' = 'date',
  'projection.dt.format' = 'yyyy-MM-dd',
  'projection.dt.range' = '2024-01-01,NOW',
  'storage.location.template' =
    's3://my-bucket/orders/dt=${dt}/'
);

Query it, and watch what gets scanned

Query it, and watch what gets scanned

With the table in place, the partition column behaves like any other column, with one difference: filtering on it decides which folders are read at all.

SELECT
  product_id,
  SUM(quantity) AS units,
  SUM(price * quantity) AS revenue
FROM orders
WHERE dt >= '2026-09-01'
  AND dt < '2026-10-01'
GROUP BY product_id
ORDER BY revenue DESC;

AWS’s documentation states it plainly: if you specify the partition in the WHERE clause, Athena scans the data only from that partition. Leave the filter out and the same query reads every day you have ever stored.

Athena reports data scanned for every query, in the console and in the query’s statistics. Make it a habit to read that number before the result. It is the bill.

Four patterns worth knowing

Four patterns worth knowing

The queries below run against a small e-commerce dataset in Athena: sessions, orders, customers and products in a database called ecommerce_demo. Each was validated on Athena before it was published here.

Join and aggregate across tables

SELECT
  s.source_medium,
  COUNT(DISTINCT s.session_id) AS sessions,
  COUNT(DISTINCT o.order_id) AS orders,
  SUM(p.price * o.quantity) AS revenue
FROM ecommerce_demo.sessions s
LEFT JOIN ecommerce_demo.orders o
  ON s.session_id = o.session_id
LEFT JOIN ecommerce_demo.products p
  ON o.product_id = p.product_id
WHERE s.date >=
  date_add('day', -30, current_date)
GROUP BY s.source_medium
ORDER BY revenue DESC;

Standard joins work as you expect. Date arithmetic uses Trino functions: date_add, date_diff and date_trunc, with the unit as a quoted string.

Select only the columns you need

SELECT date, source_medium, device_category
FROM ecommerce_demo.sessions
WHERE date >= DATE '2026-01-01';

On Parquet or ORC this reads three columns, not the whole row. On CSV or JSON it reads everything regardless, which is the strongest argument for columnar files.

Count distinct values cheaply

SELECT
  date_trunc('month', s.date) AS month,
  approx_distinct(s.customer_id) AS customers
FROM ecommerce_demo.sessions s
GROUP BY 1
ORDER BY 1;

approx_distinct returns an estimate using far less memory than COUNT(DISTINCT ...). For a trend line over a large table it is usually the right trade.

Rank within groups

SELECT category, product_name, revenue
FROM (
  SELECT
    p.category,
    p.product_name,
    SUM(p.price * o.quantity) AS revenue,
    ROW_NUMBER() OVER (
      PARTITION BY p.category
      ORDER BY SUM(p.price * o.quantity) DESC
    ) AS rn
  FROM ecommerce_demo.orders o
  JOIN ecommerce_demo.products p
    ON o.product_id = p.product_id
  GROUP BY p.category, p.product_name
)
WHERE rn <= 3;

Window functions are fully supported, so “top three products per category” needs no self-join.

Convert raw files to Parquet with CTAS

Convert raw files to Parquet with CTAS

If your data arrives as CSV or JSON, the cheapest improvement is to rewrite it once as partitioned Parquet. CREATE TABLE AS SELECT does it in one statement:

CREATE TABLE orders_parquet
WITH (
  format = 'PARQUET',
  write_compression = 'SNAPPY',
  external_location =
    's3://my-bucket/orders_parquet/',
  partitioned_by = ARRAY['dt']
) AS
SELECT
  order_id,
  customer_id,
  product_id,
  quantity,
  price,
  dt
FROM orders_raw;

Two rules from the CTAS documentation catch people out. Partition columns go last in the SELECT list. And one CTAS statement can write at most 100 partitions, so a long history is converted in batches, with INSERT INTO for the rest.

What makes Athena fast and cheap

What makes Athena fast and cheap

Every tuning technique in Athena is a way of reading fewer bytes.

  • Partition on what you filter by. Almost always a date. Add a second key only if most queries filter on it too.
  • Store columnar, compressed files. Parquet or ORC, so a query reads only the columns it names.
  • Avoid many small files. Thousands of kilobyte-sized objects cost more in S3 requests and planning than in scanning. Compact them.
  • Filter early and name your columns. SELECT * over a wide table defeats the columnar format.
  • Use partition projection for tables with many partitions, so the engine does not have to look each one up.

Where Athena fits, and where it does not

Where Athena fits, and where it does not

Athena is a strong choice when the data already lives in S3 and the work arrives in bursts: log analysis, exploring exports from other systems, validating a pipeline, occasional reporting. You pay nothing between queries.

It is a weaker choice when many people need fast answers all day. Athena has per-account quotas on concurrent queries, and unless a query can reuse a recent result, each person who runs it pays for the scan again. Updates and deletes need Iceberg tables; plain external tables are append-only.

Compared with the alternatives:

  • Amazon Redshift keeps compute available, so it suits steady dashboard traffic and heavy joins. You pay for that availability whether or not queries run.
  • BigQuery is also serverless and also has a scan-based price, but stores data in its own managed format by default.
  • Snowflake and Databricks bill for compute time, not bytes read. Snowflake pricing and Databricks pricing cover how those bills are built.

The data warehouse comparison puts the five side by side.

From queries to reports people read

From queries to reports people read

A query that an analyst runs once is cheap in Athena. The same query behind a dashboard that ten people open is ten scans, and on a scan-priced engine that difference is the whole bill. The answer is the same as on any warehouse: write the query once, run it on a schedule, and let people read the result.

That is the job OWOX Data Marts does on top of Athena. It does not transform your data or change what Athena charges. You connect Athena as a storage with a region, an output bucket for query results and an IAM access key, and the analyst’s SQL becomes a Data Mart: one named, validated definition.

Data Setup of a SQL Data Mart in OWOX Data Marts on an AWS Athena storage, showing the region, the output bucket and a query joining sessions, orders, customers and products with a “Valid SQL code” check – the analyst’s SQL, kept in one place

Each Data Mart can then be delivered as a report to Google Sheets, Data Studio, Slack or email. A Google Sheets report writes the rows into the sheet when it runs, so people opening the sheet do not trigger a scan. One scheduled run a day is one scan a day, however many readers there are.

Data Marts list in OWOX Data Marts filtered to AWS Athena storage, showing nine Data Marts fed by ad platforms, Shopify and SQL – a reporting layer that leaves the data in S3

Most of the Data Marts in that list are connectors: they load ad platform and Shopify data into tables in the Athena storage on a schedule, and those tables are queried with the same SQL shown above. The Athena to Google Sheets connector page shows the destination side, and Data Mart management explains how definitions are owned and shared.

Your New Normal

Turn your data into decisions.

Governed data marts give you the clean foundation ML needs to actually work.

  • No AI hallucinations
  • Analyst-governed definitions
  • Every number traces to SQL
Get started free

FAQ

Frequently Asked Questions

How much does Amazon Athena cost per query?

Athena charges for the data a query scans: $5 per terabyte on the pricing page in October 2026, rounded up to the nearest megabyte, with a 10 MB minimum per query. Partitioned tables and columnar formats such as Parquet reduce the bytes scanned and so the cost. You also pay standard S3 and Glue Data Catalog rates, and provisioned capacity is available at $0.30 per DPU-hour.

How does the AWS Glue Data Catalog integrate with Athena for metadata management?

The AWS Glue Data Catalog serves as a centralized metadata repository for Athena, storing table definitions, schemas, partitions, and locations of data in S3. Athena queries interpret the stored metadata at runtime to understand how to scan and parse underlying files, making accurate schema and partition management critical for query correctness, performance, and cost control.

What are the limitations of Amazon Athena?

Cost and speed depend on how the files are laid out, so unpartitioned text data is slow and expensive to query. There is no always-on compute, there are per-account quotas on concurrent queries, and updates and deletes need Iceberg tables. For steady dashboard traffic and heavy joins a warehouse such as Amazon Redshift fits better, and for long-running batch processing Spark on EMR does.

What common use cases are best suited for AWS Athena on S3?

Athena excels at ad-hoc exploration and analysis of large, append-only datasets like application and access logs, clickstream data, marketing and advertising exports, IoT telemetry, and operational snapshots. It is commonly used for log analytics, early-stage analytics, data engineering validation, and lightweight business intelligence without cluster management.

What data formats and partitioning strategies optimize Athena’s performance and cost?

For optimal performance and cost savings, use columnar formats like Parquet or ORC instead of CSV or JSON, as Athena can scan only relevant columns. Partition data primarily by time (such as date) and add additional partitions only if they significantly reduce query scope. Avoid small files by compacting data into larger files to reduce query overhead.

How does Athena differ from traditional data warehouses like Redshift or BigQuery?

Unlike traditional warehouses, Athena is a serverless query engine that reads directly from external storage (S3) without managing internal storage or clusters. It provides on-demand compute with pay-per-TB scanned pricing and is optimized for reading and analyzing lake data rather than heavy transformations or high-concurrency BI. Redshift and BigQuery manage storage internally and are better suited for heavy dashboard workloads and complex joins.

What are the advantages of using AWS Athena for analytics on S3 data lakes?

Athena offers low operational overhead with no cluster management, automatic scaling, and pay-per-query pricing based on data scanned. It supports standard ANSI SQL and integrates tightly with AWS services like Glue, Lake Formation, and QuickSight, making it ideal for exploratory analysis, log analytics, and serverless querying over large S3 datasets.

What is Amazon Athena and how does it work on S3 data?

Amazon Athena is a serverless, interactive SQL query engine that reads data directly from Amazon S3, using schemas defined in the AWS Glue Data Catalog. It allows you to run standard SQL queries on data stored in S3 without loading it into a separate database or provisioning any clusters.

Who wrote this

Ievgen Krasovytskyi

Ievgen Krasovytskyi Head of Marketing

Ievgen Krasovytskyi is the Head of Marketing at OWOX, leading strategy across content, SEO, product marketing, and AI-powered automation. With deep expertise in analytics infrastructure, data warehouses, and marketing technology, he builds systems that connect marketing performance to business outcomes. Ievgen writes about SaaS growth, analytics workflows, and the future of AI in marketing operations.