We migrated a 105-million-row PostgreSQL database into Google Cloud Spanner with Wirekite’s bulk data loader. On an 8-node Spanner instance the full load finished in 6 minutes 59 seconds, averaging 250,600 rows/sec and sustaining a peak of 648,000 rows/sec.
The result
| config | load time | average | peak (1 min) | peak (20 s) |
|---|---|---|---|---|
| Spanner 4 nodes (4,000 PU) | 9 m 05 s | 192,700 rows/s | 225,000 rows/s | 463,000 rows/s |
| Spanner 8 nodes (8,000 PU) | 6 m 59 s | 250,600 rows/s | 648,000 rows/s | 939,000 rows/s |
Doubling the Spanner instance from 4 to 8 nodes scaled peak throughput almost linearly — 463K → 939K rows/sec at the 20-second peak (2.03×). Average throughput scaled sub-linearly (1.30×) only because the fixed ramp-up is a bigger slice of the shorter run; on a larger dataset the average converges toward the peak.
The source
| Source | PostgreSQL 16 |
| Total rows | 105,019,164 |
| Database size | ~33 GB |
Three large tables of 35 million rows each (≈11 GB apiece) plus 14 small tables. Each large table is 16 columns wide — an integer primary key, several integer and varchar columns, a date, a timestamp, and a bytea blob — averaging ~300 bytes per row.
The target
Google Cloud Spanner, tested at two sizes: 4 nodes (4,000 processing units) and 8 nodes (8,000 PU). Writes go through Spanner’s BatchWrite API.
Throughput over the run (8 nodes)
The loader ramps as data arrives and Spanner spreads the write load across its nodes, reaching full speed in the back half of the run:
| elapsed | rate |
|---|---|
| 0–1 min | 19,900 rows/s |
| 1–2 min | 63,100 rows/s |
| 2–3 min | 124,500 rows/s |
| 3–4 min | 47,100 rows/s (brief dip as the loader transitions between tables) |
| 4–5 min | 223,400 rows/s |
| 5–6 min | 624,100 rows/s |
| 6–7 min | 648,300 rows/s |
The final two minutes — a sustained 624,000–648,000 rows/sec — represent the true Spanner write capacity for this workload on 8 nodes: about 81,000 rows/sec per node for 16-column, ~300-byte rows.
What this means
A 105-million-row PostgreSQL database lands in Cloud Spanner in under seven minutes. Bulk migrations and initial syncs that traditionally run for hours — and hold cutover windows hostage — collapse into a coffee break. And the throughput scales with the instance: add Spanner nodes and you get proportionally more peak write capacity.