Can a Mac Mini Handle 100 Million Rows?
What is this, and why should you care?
I wanted to answer one silly question: how far can a plain Mac Mini M4 push a database before it falls over? Not a giant cloud box. Not a 64-core server. A Mac Mini. The little thing that sits on your desk.
So I took a real problem - storing LLM traces (more on that in a sec) - and threw a growing pile of data at two very different databases:
- Postgres, the row store we all know and love.
- ClickHouse, the columnar database built for analytics.
I started at 1 million rows and climbed all the way to 100 million. Same data on both. Same machine. Same questions.
If you build stuff with LLMs, run dashboards on a database, or you've ever wondered "should I really move off Postgres?" - this one is for you. By the end you'll know where each database wins, where it hurts, and how much a humble Mac Mini can actually take.
Spoiler: the result surprised me. Nobody died. The story is still brutal. ๐
Prerequisites โ
Nothing scary. You're good if you have:
- A basic idea of SQL (you know what a row and a query are).
- Heard of Postgres.
- Columnar Databases. You can learn from my friend's article: Here [Must Read]
- A rough idea of "LLM observability". If not, the next section fixes that.
- A machine to try it on. Mine was a Mac Mini M4 Pro.
That's it. Let's dig in.
๐ค The Problem (and why it pokes everyone)
Okay, quick story. When you build an app on top of an LLM, you're kind of flying blind. Which model got called? How many tokens did it burn? What did it cost? Why was it slow?
So people log everything. Every LLM call, every tool call, every step becomes a "trace". One row each. This is what tools like Langfuse do (it's a popular open-source LLM observability platform).
Here's the catch. Traces pile up fast. One chat can be 5-8 rows. Multiply by thousands of users. You hit millions of rows before you know it. And the dashboards on top? They aren't simple lookups. They're big questions:
- "Cost per model for the last 90 days."
- "p95 latency across 40 million calls."
That's a lot of number-crunching on every single refresh.
Langfuse started on Postgres. As traces grew, those dashboard queries got slow. So in their v3 rewrite, they moved trace storage to ClickHouse. And in early 2026, ClickHouse acquired Langfuse. Actual Story which I tried to mimic in my experiment: Here
That made me curious. Was the move actually worth it? Or just hype? I didn't want to read about it. I wanted to see it. On the most normal machine I had lying around, a Mac Mini. Two birds, one stone: test the migration story, and find the limits of the little box. ๐ฆ๐ฆ
๐งช The Experiment
No code here, just the plan. I wrote four small scripts. Here's what each one did.
1. The data faker ๐ฒ
Goal: make realistic fake LLM traces on the fly, without saving one giant file. It generated a mix of models (GPT, Claude, embeddings), token counts, costs (cost = tokens ร price), latencies, and a few errors here and there. Same seed every run, so both databases got the exact same rows. That part is key. It's the only way the fight stays fair.
Result: I could summon 1 row or 100 million, identical on both sides.
2. The ClickHouse runner ๐ก
Goal: load the data into ClickHouse and time everything. It built the table, then loaded data in steps - 1M, 5M, 10M, 25M, 50M, 100M. At each step it measured four things: ingest speed, disk used, RAM used, and how long three real queries took. All the records are shared in the last part of this article.
Result: one clean row of numbers per step, saved to a CSV.
3. The Postgres runner ๐
Goal: do the exact same thing for Postgres. Same data, same steps, same three queries. And I gave Postgres its best shot - proper indexes, its fastest bulk-load path (COPY), one query at a time. No handicap.
Result: matching numbers, so I could line them up side by side.
Those three queries, by the way, are the ones that actually matter for observability:
- Fetch one full trace (a point lookup).
- A dashboard aggregation (cost + latency per model, last 90 days).
- A metrics query (crunch stats across all of history).
4. The report maker ๐
Goal: turn the boring CSV into charts I could actually read. It spat out a PDF with everything - ingestion, disk, memory, query latency.
Result: the pretty pictures you're about to see.
Then I hit go and let the Mac Mini grind for a few hours. Watched the temps of my Mac in a corner. Drank some Irani Tea โ (IFYKYK)
๐ The Results
Alright. The good stuff. First, the headline I did not expect: both databases finished all 100 million rows. Nobody crashed. Nobody ran out of memory. On a Mac Mini! My itsy-bitsy aluminium box did surprise me.
So if your only question was "can a Mac Mini hold 100M rows of traces?" - yes. Easily. Both did.
But "finished" and "usable" are very different things. Look closer and the gap gets wild.
Ingesting the data ๐
ClickHouse ingested at a flat ~78,000 rows/sec the whole way. 1 million or 100 million, it didn't care. Straight line ๐๐ค๐ป
Postgres started around 32,000 rows/sec... and slowly sank to ~14,000 rows/sec by 100M. The more data it held, the slower new inserts got. Those indexes aren't free.
At 100 million rows, ClickHouse was ingesting about 5.6ร faster.
Disk space ๐ฟ
Same 100 million rows:
- ClickHouse: 48 GB
- Postgres: 116 GB
ClickHouse packed it down about 2.4ร smaller. Its columns compress really well (~5.5ร internally). On a 300 GB SSD, that's the difference between "loads of room" and "getting nervous".
The queries ๐ถ๏ธ
This is where it gets spicy! Here's the twist. It's not a clean sweep.
Fetching one trace? Postgres wins. Every. Single. Time. Postgres did it in ~0.03 ms. ClickHouse took ~3 ms. That's Postgres being roughly 100ร faster, and it stayed fast even at 100M rows. Grabbing one row by its ID is a row store's home turf. ClickHouse just isn't built for that, and it shows.
But the dashboard query? Whole different movie. At 1 million rows, both were fine (Postgres ~228 ms, ClickHouse ~15 ms). At 100 million rows:
- ClickHouse: 284 ms
- Postgres: 49,085 ms
That's not a typo. Postgres took about 49 seconds for one dashboard query. Now imagine refreshing a dashboard that takes 49 seconds. ๐ฌ
The metrics query was even rougher. Postgres hit ~70 seconds at 100M. ClickHouse stayed around half a second.
Memory ๐ง
Both barely touched RAM. One query at a time, nobody needed much - Postgres sat around a couple hundred MB, ClickHouse under a gig. The 24 GB Mac Mini was honestly bored. (Throw heavy concurrent traffic at it and this changes. But that's a different test for another day!)
The whole fight in one table
At 100 million rows, on one Mac Mini:
| Metric | ClickHouse | Postgres |
|---|---|---|
| Ingest speed | ~78K rows/s | ~14K rows/s |
| Disk used | 48 GB | 116 GB |
| Fetch one trace (p95) | ~3 ms ๐ | ~0.03 ms โ |
| Dashboard query (p95) | 284 ms โ | ~49 sec ๐ต |
| Metrics query (p95) | ~0.5 sec โ | ~70 sec ๐ต |
| Peak RAM | ~950 MB | ~134 MB |
For all of us who love to see actual numbers ๐ฏ
So what did I actually learn?
A few things stuck with me.
Nobody "won". Postgres crushes point lookups. ClickHouse crushes analytics. This was never really ClickHouse vs Postgres. It's OLTP vs OLAP, and I got to watch it play out live.
This is exactly why Langfuse moved. An observability product lives on dashboards. Cost per model. Latency percentiles. Usage over time. Those are analytical queries over millions of rows. On Postgres at scale, that's a 49-second dashboard. On ClickHouse, it's a blink. The migration wasn't hype - for that use case, it's the whole ballgame.
A Mac Mini is a beast. 100 million rows, two databases, a few hours, zero cloud bill. It didn't even sweat on memory. If you're prototyping something data-heavy, don't sleep on the little box on your desk.
Compression is a quiet flex. 48 GB vs 116 GB for the same data adds up fast when you're the one paying for the disk. ๐
Wrapping up
That was a fun one. One Mac Mini, 100 million LLM traces, and a very clear picture of who's good at what.
If you're storing LLM traces: keep Postgres for the transactional bits, and reach for a columnar DB like ClickHouse when the dashboards start to crawl.
I'm still wondering if the idea is helpful to someone. I might open source the scripts if you appreciate this experiment. If you liked this content you can follow me on Twitter at @kitarp29 for more!
Thanks for reading my article ๐
Comments
No comments yet. Start the discussion.