AI or Obsolete: Lessons from the CDOs winning with AI

Get the report

ETL Process Optimization

A Practitioner's Guide to Faster, Cheaper, More Reliable Pipelines

ETL process optimization is the work of finding out which part of a pipeline is actually slow, expensive, or unreliable, and fixing that part instead of rebuilding the whole thing. It touches four layers: how data gets extracted, how it gets transformed, how it gets loaded, and how the whole sequence is orchestrated and monitored. Get the diagnosis wrong and you'll spend a sprint adding compute to a problem that was never about compute.

That last point is the one most guides skip. A pipeline that ran fine at ten thousand rows a day and crawls at ten million almost never has a fundamentally broken design. It has one load pattern, one join, or one scheduling decision that nobody revisited once the data grew. Optimization is the process of finding that one thing.

Why This Matters More Than It Used To

Data volumes keep climbing, and so does the cost of ignoring the problem. Gartner's data and analytics predictions for 2026 point to a shift toward AI-driven pipeline operations, where metadata, lineage, and governance move from nice-to-have to prerequisite as more of the workload runs autonomously. Whether or not you're there yet, the baseline still applies: a pipeline you can't measure is a pipeline you can't optimize, and the teams getting ahead of this are the ones treating monitoring as part of the build, not something bolted on after an incident.

Baseline First. Always.

Before you touch a single line of transformation logic, measure what you have. At minimum, log these four numbers per pipeline run, and keep them somewhere queryable, a time-series table in your warehouse works fine:

  • Runtime, end to end and per stage
  • Cost per run, or at minimum compute-seconds consumed
  • Rows processed, so you can tell a genuine slowdown from a data-volume increase
  • Failure rate, over a rolling window, not a single bad day

Skip this step and you'll optimize based on a hunch. Most hunches are wrong. The engineer who assumes the transformation step is the bottleneck is right maybe half the time; the other half, it's a source system throttling API calls, or three jobs firing at the same scheduled time and fighting over warehouse compute. You won't know which one you have until you've measured it.

Extraction: Stop Pulling the Whole Table Every Time

The single most common mistake in ETL process optimization is extracting more data than the pipeline actually needs, every single run.

Incremental loading fixes this. Instead of a full-table pull, you read only the rows that changed since the last run, using a timestamp column, an auto-incrementing ID, or change data capture (CDC) reading directly off the source database's transaction log. CDC is the strongest option where it's available: it catches deletes and out-of-order updates that a simple "updated_at greater than yesterday" filter will miss.

Pushdown filtering matters just as much and gets ignored more. If your extraction step pulls a full table into a staging area and only then filters it down, you're paying the network and compute cost of moving data you're about to throw away. Push the filter to the source query instead, so the source system only sends what you're going to keep.

The signal that you have an extraction problem, not a transformation problem: your pipeline's early stages take disproportionately long relative to the data volume actually flowing downstream, or your source system's API rate limits are the thing capping your runtime, not your warehouse.

Transformation: ELT Wins More Often Than Not, But the Choice Is Real

This is where the ETL versus ELT decision actually lives, and it's worth being precise about it rather than treating it as a buzzword.

Traditional ETL extracts data, transforms it in a separate compute layer (a dedicated ETL engine or scripting environment), and only then loads the clean result into the warehouse. ELT flips the order: extract, load the raw data into the warehouse or lakehouse first, then transform it there using the engine's own compute.

ELT has become the default for a specific reason: cloud warehouses got very good at SQL transformation, and you're paying for that compute whether you use it or not. Snowflake's own guidance on optimizing pipeline performance is built around this assumption, using the warehouse's query optimizer and caching layers rather than routing data through an external transformation step. Databricks' Delta Lake documentation makes a similar case from the lakehouse side: predictive optimization and compaction work best when the transformation logic runs where the data already lives, not somewhere else.

ETL still has a role. If you're dealing with sensitive data that needs to be masked or tokenized before it lands anywhere, or a compliance requirement that data can't touch a shared environment even briefly in raw form, transforming before load can be the right call. That's a real trade-off, not a legacy habit.

Inside the transformation step itself, two things matter more than most teams realize:

Set-based operations beat row-by-row logic. A transform that loops through records one at a time will always lose to the same logic expressed as a single SQL statement operating on the whole set. This is the single easiest win to miss, because row-by-row code is often easier to write and debug during development, and nobody revisits it once it's in production.

Model layering keeps transformations testable. If you're working in dbt, the staging, intermediate, and mart layering pattern exists for a reason: it isolates a bad join to one layer instead of letting it ripple through a single, giant, unmaintainable query. Teams that skip layering usually pay for it later, when a schema change breaks a transformation nobody remembers writing.

Load: The Part Everyone Assumes Is Fine Until It Isn't

Loading looks simple, which is exactly why load-layer problems go unnoticed the longest.

Bulk writes over row-by-row inserts. Loading a million rows one insert statement at a time is dramatically slower than a single bulk load operation, and the gap gets wider as volume grows. If your load step is doing the former, this is usually the cheapest fix on the whole list.

File sizing, for anything landing in object storage first. Too many small files creates overhead on every downstream read; too few, oversized files kill parallelism. Neither extreme is obvious from the outside, both show up as "the load step is slow for no clear reason."

Idempotency. A pipeline that produces the same result whether it runs once or gets accidentally retried three times is a pipeline you can safely automate retries on. One that duplicates data on a retry is a pipeline where every failure becomes a manual cleanup job. This one isn't a performance optimization so much as a reliability one, but it belongs in the same conversation, because a pipeline that needs babysitting after every failure isn't actually optimized, whatever its runtime looks like.

Orchestration and Monitoring: Where Slow Problems Hide the Longest

A pipeline can have perfectly tuned extraction, transformation, and load steps and still run badly if the orchestration layer is working against it.

The most common version of this: every job scheduled to kick off at the top of the hour, all competing for the same warehouse compute at the same moment. Staggering schedules, or moving to event-driven triggers instead of fixed-time ones, solves this without touching a single transformation.

Schema drift deserves its own line here, because it's the failure mode that looks like a mystery until you know to look for it. A source system adds a column, renames a field, or changes a data type, and a pipeline built to expect the old shape either breaks outright or, worse, silently ingests wrong data. Monitoring for schema drift specifically, not just job success or failure, is what separates a pipeline that fails loudly from one that fails quietly and erodes trust in the data for weeks before anyone notices.

AWS's Well-Architected Data Analytics Lens treats observability as one of its core design principles for analytics workloads, not an afterthought bolted on once something breaks. That's the right instinct: build the monitoring in alongside the pipeline, and you catch drift and SLA misses before they become a Monday-morning fire.

Cost: Performance and Spend Are the Same Conversation

Every technique above affects cost as a side effect, but a few things are worth calling out on their own.

Right-size compute before you scale it. An oversized warehouse sitting idle between bursts costs the same as a correctly sized one doing real work. This sounds obvious and gets ignored constantly, because scaling up is the easy fix when a job is running slow, and nobody circles back to scale it down once the immediate problem is solved.

Caching and result reuse. If the same query, or something close to it, runs repeatedly against data that hasn't changed, caching layers exist specifically to avoid paying compute for the same answer twice. Snowflake's built-in result cache and Databricks' predictive optimization for Delta tables both exist to catch exactly this pattern.

Incremental refresh design. For any transformation that runs on a schedule rather than a full rebuild, keeping the volume of changed data small relative to the total dataset is what determines whether that refresh scales cheaply or expensively as data grows. This ties directly back to the extraction section above: if you're not extracting incrementally, you can't refresh incrementally either, and the cost compounds at every layer downstream.

ETL vs. ELT at a Glance

 Traditional ETLModern ELT
Where transformation happensDedicated transformation engine, outside the warehouseInside the warehouse or lakehouse, using its own compute
LatencyHigher, data waits for an external processLower, no intermediate hop
Cost modelSeparate compute for transformationUses compute you're already paying for
Best fitSensitive data needing masking before it lands anywhere; strict compliance on raw data exposureMost cloud-native analytics workloads at scale
Tooling maturity in 2026Mature, but increasingly a legacy patternThe default for new pipeline builds

A Framework You Can Actually Apply

  1. Baseline. Log runtime, cost, rows processed, and failure rate per run before changing anything.
  2. Diagnose. Compare the numbers against where time and cost actually concentrate: extraction, transformation, load, or orchestration. Don't guess.
  3. Fix the specific layer. Apply the technique that matches the actual bottleneck, not the one that's easiest to implement.
  4. Re-measure. Confirm the fix moved the number you were trying to move, and didn't just shift the bottleneck one layer over.

Repeat this loop rather than treating optimization as a one-time project. Data volumes grow, source systems change, and a pipeline that was well-tuned six months ago can drift back into needing attention without anyone changing a line of its logic.

Where to Go From Here

If your pipelines are past the point of manual tuning, or if a legacy platform is the actual ceiling rather than any specific inefficiency, that's a migration conversation, not an optimization one. And if the real constraint is that your team doesn't have the hours to keep revisiting load patterns as data grows, Maia optimizes the ETL process continuously rather than on a quarterly basis (link to Maia.ai blog once published), which is a different way of solving the same problem this guide walks through by hand.

See also: ETL vs. ELT, ETL automation, and the Maia glossary entry on ETL process optimization for a shorter reference version of this same topic.

Frequently Asked Questions: ETL Process Optimization

Start by measuring runtime, cost, and failure rate per run, then diagnose which layer, extraction, transformation, load, or orchestration, actually accounts for the slowdown before applying a fix. The most common wins are incremental extraction, pushdown transformation, bulk loading, and staggered scheduling.

Usually, for cloud-native analytics workloads, because ELT transforms data inside the warehouse using compute you're already paying for, rather than routing it through a separate transformation layer first. ETL still has a place where data needs to be masked or transformed before it can land anywhere, even briefly, in raw form.

Usually, for cloud-native analytics workloads, because ELT transforms data inside the warehouse using compute you're already paying for, rather than routing it through a separate transformation layer first. ETL still has a place where data needs to be masked or transformed before it can land anywhere, even briefly, in raw form.

Right-size compute to actual workload rather than peak demand, use built-in caching and result reuse for repeated queries, and design transformations to run incrementally on changed data rather than reprocessing full datasets on every run.

No. ELT removes one layer of potential inefficiency (the separate transformation hop) but every other layer, extraction, load, orchestration, and the transformation logic itself, still needs the same diagnostic approach.

Get started today with a free Matillion account