DSC3103 ยท Module 2 of 9

Pipelines: ETL vs ELT, Parquet & Idempotency

Build modular, repeatable pipelines with columnar storage (Lab 3)

~57 min to study properly

A notebook that only works when you run cells in a secret order is not a pipeline. In Lab 3 we refactored our code into modular stages: profile โ†’ validate โ†’ clean โ†’ store, orchestrated by run_pipeline.py.

Checkpoint ยท the examiner asks

Define idempotency in data pipelines. Why does a naive append mode break idempotency on retries, and how do you engineer both file outputs and database loads to be idempotent?

In one minute

A pipeline is modular stages (profile โ†’ validate โ†’ clean โ†’ store) that can be re-run safely. ETL transforms before loading; ELT loads raw first and transforms in-engine. Parquet is columnar, typed and compressed, so queries read only the columns they need. Idempotency means running twice leaves the same state: use atomic temp-file swaps (os.replace) and primary-key upserts or partition overwrites, never blind appends.

Traps examiners look for
  • Using append mode โ€” every retry or backfill duplicates rows.
  • Writing directly to the final file so a crash leaves it half-written.
  • Thinking Parquet compression is the only win โ€” column pruning is usually bigger.
Read

Study notes

01From notebook to pipeline

A notebook is great for exploring and terrible for production: cells can run out of order, state hides in memory, and "it worked yesterday" is not a guarantee. A pipeline is the same logic split into small, named stages with clear inputs and outputs:

profile.py โ†’ validate.py โ†’ clean.py โ†’ store.py, orchestrated by run_pipeline.py.

Each stage reads files, does one job, writes files and logs what it did (row counts, durations). That gives you three things a notebook can't: you can rerun one stage without the others, you can test each stage, and a scheduler like Airflow can retry the stage that failed instead of everything.

02ETL vs ELT

ETLELT
OrderExtract โ†’ Transform โ†’ LoadExtract โ†’ Load โ†’ Transform
Where transforms runin Python on a staging machineinside the warehouse/engine (SQL, DuckDB)
Raw data kept?often notyes โ€” raw lands first
Good whendata is small, transforms are complex Pythonthe engine is powerful and you want to re-transform later

Modern analytics leans towards ELT because storage is cheap and engines like DuckDB, BigQuery or Snowflake are fast: land the raw data once, then build cleaned tables with SQL that can be changed and rerun at any time. Our course pipeline is a hybrid โ€” Python cleaning, then DuckDB for modelling and queries.

03Why Parquet beats CSV

CSV is row-oriented text: every query has to read and parse every byte of every column, and the types are guessed each time ("0012" becomes 12, dates become strings).

Parquet is a binary, columnar format:

  • Column pruning โ€” values of each column are stored together, so SELECT AVG(price_ugx) reads only that column. Reading 2 of 10 columns reads ~20% of the data.
  • Compression that works โ€” a column of market names repeats the same few strings, so dictionary + run-length encoding shrinks it dramatically.
  • Typed schema โ€” integers stay integers, dates stay dates.
  • Row-group statistics โ€” each block stores min/max per column, so a filter like date >= '2025-03-01' can skip whole blocks (predicate pushdown).

Bytes scanned โ‰ˆ CSV size ร— (columns read รท total columns) รท compression ratio.

04Idempotency, atomic writes and upserts

A stage is idempotent if running it once or ten times on the same input leaves the same result: f(f(x)) = f(x). This matters because schedulers will retry failed tasks and run backfills.

The classic violation is append: each retry inserts the batch again, so a table with 10,000 rows and a 1,500-row batch has 14,500 rows after three runs instead of 11,500.

Two standard fixes:

  • Files: write to a temporary path and atomically swap it in โ€” os.replace("out.parquet.tmp", "out.parquet"). Readers see either the old complete file or the new complete one, never half a file. Or overwrite the whole partition for that date.
  • Tables: enforce a primary key on the business key and upsert (INSERT OR REPLACE, ON CONFLICT DO UPDATE), or DELETE WHERE date = :d then INSERT, inside one transaction.
Watch it done

Worked examples

Worked example 1

How much does DuckDB scan?

A 10-column market table is 300 MB as CSV. Stored as Parquet with 4ร— compression, how much does a query reading 3 columns scan?

    Worked example 2

    Counting the damage of append

    A table has 8,000 rows. A 1,200-row batch (300 of its keys already exist) is loaded, the task fails at the end, and Airflow retries twice. How many rows with append, and how many with an upsert?

      Vocabulary

      Key terms

      Why Parquet + DuckDB beats CSV by 20ร—โ€“100ร—

      Because all values of a column sit together in Parquet, a single column of market names like 'Owino' repeated 50,000 times collapses to a tiny integer dictionary plus run-length encoding โ€” shrinking size by 80%+ and allowing SIMD vectorised scans.

      Practise

      Quick check

      0 of 8 correct so far. Wrong answers come with an explanation โ€” and the buddy can unpack them.

      Q1A table has 12 columns (each 8 bytes/row) and 1,000,000 rows. A query selects only 2 columns. Roughly how much less raw data does columnar storage scan than row-oriented CSV?

      Q2Why write to 'market_prices.parquet.tmp' and call os.replace() instead of writing directly to 'market_prices.parquet'?

      Q3In ELT, where do transformations usually run?

      Q4Which Parquet feature lets a date filter skip whole blocks of data?

      Q5Why is os.replace(tmp, target) used when writing output files?

      Q6f(f(x)) = f(x) is the definition ofโ€ฆ

      Q7A CSV column contains "0012". What can go wrong that Parquet avoids?

      Q8What's the main benefit of splitting a pipeline into stages?

      Exam-style

      Written practice

      Short answer5 marks

      Compare ETL and ELT and say which you would choose for the Uganda market-price project, with a reason.

      Short answer6 marks

      Explain three reasons Parquet is preferred over CSV for analytical storage.

      Long answer12 marks

      An Airflow task loads a daily batch into fact_market_prices using pandas to_sql(if_exists='append'). It failed twice last week and was retried. Explain what happened to the data, how you would detect it, and how you would redesign the load to be idempotent for both the Parquet files and the database table.

      Watch

      Videos

      Fresh picks are chosen by AI every day.
      Hands-on

      Parquet Columnar I/O & Idempotency Simulator

      4 guided tasks: predict, experiment, explain โ€” then challenge yourself. Plus 2 coding exercises you run right in the browser.

      Start the lab