# Performance

> How fast iceberg is: measured numbers, what profiling found, and its benchmark history.

[magmalake](https://magmalake.dev/) [iceberg](https://magmalake.dev/s/iceberg)

###  Table and file formats

| Operation | magmalake | Reference |
| --- | --- | --- |
| Iceberg scan, 1M rows — 1 core / 4 workers zstd, six columns; best-of-three warm, not the percentile harness | 30.3 ms / 9.9 ms | pyarrow on the same four data files: 27.3 ms one thread, 8.8 ms threaded — about 1.1× ahead of us at either thread count. PyIceberg 0.11.1 does the whole scan in 8.0 ms on pyarrow's pool. |
| Iceberg scan, nested columns, 200k rows a struct and a list column, 1 core | 8.7 ms | PyIceberg 5 ms on pyarrow's thread pool in the same runs — about 1.7× faster. Nested reconstruction is the slowest path we have: on the mixed Parquet file in parquet's table, Dremel assembly into Arrow buffers is 30% of the read and decompression another 25%. |
| Iceberg scan, 2M rows over eight files 1 / 2 / 4 / 8 workers, to\_batches | 60.2 / 32.1 / 19.3 / 14.9 ms — 4.0× at eight | eight files give the workers more to divide than the four-file table above; PyIceberg reads the same table in 15 ms |
| Iceberg append, 1M rows data files, manifests and commit | 191 ms | PyIceberg 156 ms, writing three times the Parquet bytes |
| Iceberg scan planning, 500 manifests | 19.5 ms for 2,000 file tasks | 28.9 µs fixed per manifest, 10.2 µs of that the file read itself |

scroll the table sideways →

Apple M4 — ten cores, four of them performance — macOS, stable Mojo 1.0.0, with nothing else building on the machine. Measured on 5 September 2026; the Iceberg rows on 15 September, the boundary rows on 19 September. [How these were measured](https://magmalake.dev/performance#method).

### Found by profiling

**500 byte-identical manifest schemas, each parsed from scratch.** Caching the parsed schema and the plan is what puts scan planning at 21 ms; it was three times that before.

### A whole query, end to end

The rows above measure one tin at a time. [taxibench.example](https://github.com/magmalake/taxibench.example) measures the stack the way a caller uses it: eight analytical queries over **79,478,796 NYC taxi trips** as an Iceberg table, answered by iceberg.mojo and by PyIceberg, with every answer diffed between the two before any timing is quoted.

It is also where the last few releases came from. Profiling it found four gaps — no intra-file parallelism, no metadata-only `count()`, a residual evaluated per row, and a scan that read whole files to decode four columns of nineteen — and closing them took the suite from **0.70x to 1.34x** the speed of PyIceberg single-threaded, and to **1.68x** across ten threads.

The same repository also asks what a table format is worth by answering the same eight questions from PostgreSQL, and packages both stacks as container images — 521 MB for the Python one against 126 MB, or 57 MB without object storage.

[A magmalake project](https://magmalake.dev/)

Apache 2.0 · © 2026 Marius Seritan
