PgCache benchmarks

Engineers outside PgCache have been putting it through its paces and publishing everything (including where it didn't help!). Their results are below, along with the harness James built so you can run your own.

0

wrong answers across roughly 20,000 side-by-side checks against origin, including reads that landed during live writes

Leonardo Benedet (dashboard test not checked yet)

6.4x to 12.6x

faster on a multi-tenant SaaS dashboard with 8 queries per page. 6.4x with one user, 12.6x once origin was busy.

Leonardo Benedet

No change

on a simple lookup by id. Origin was already answering in 0.3 ms, so there was nothing for PgCache to speed up.

Hulunlante Worku

Published results

Leonardo Benedet

What a read cache is worth in front of a multi-tenant SaaS database

PgCache design partner, unpaid. Designed, ran, and published this benchmark on his own.

PgCache 0.6.2
Query Origin Postgres Through PgCache
Dashboard page (1 client) 32.2 ms 5.07 ms
Dashboard page (8 clients) 83.1 ms 7.09 ms
Dashboard page (32 clients) 291 ms 23.4 ms
Dashboard page (8 clients, 10% writes) 77.9 ms 7.55 ms
Dashboard throughput (32 clients) 110 req/s 1,370 req/s

Setup. PostgreSQL 17 on Kubernetes, with the origin, PgCache, and pgbench on three separate 8 vCPU nodes in one zone. Seven tables, 463 MB and 200 tenants, all of it fitting in the origin's memory, which is the hardest case for a cache.

Method. Each request is one dashboard page: 8 tenant-scoped queries with counts, sums, joins, and pagination. The only difference between the two paths is the connection string. PgCache ran on its defaults and was warmed until the share served from cache stopped changing, and every query in every cell was served from cache.

Author's caveat. A differential correctness check was not run against this workload. Mean latency only, no percentiles.

Leonardo Benedet

Is it worth putting a cache in front of Postgres?

PgCache design partner, unpaid. Designed, ran, and published this benchmark on his own.

PgCache 0.6.2
Query Origin Postgres Through PgCache
Point lookup (1 client) 196 µs 115 µs
Point lookup throughput (256 clients) 50,706 req/s 140,099 req/s
Point lookup throughput (prepared statements, 32 clients) 94,344 req/s 124,364 req/s
Point lookup throughput (10% writes) No gain 12,573 req/s 12,308 req/s
Range aggregate (1,001 rows) 549 µs 393 µs
Range aggregate (10,001 rows) Slower. 0.6.3 may help 2.42 ms 714.5 ms
openFGA check, p99 (160 req/s) No gain 16.17 ms 16.74 ms

Setup. Two real applications, openFGA and NetBox, then pgbench on Kubernetes with the origin, PgCache, and load generator on separate nodes in one zone. The pgbench runs used 1 million rows that fit in the origin's memory.

Method. Every campaign except the multi-tenant dashboard compared the origin's answers with PgCache's before publishing a performance number: about 20,000 comparisons, including reads during live writes, with zero differences. Results he later found were wrong are marked as retracted in the report, not deleted.

Author's caveat. The pgbench results measure the product's envelope. They are not an adoption verdict, and there is no application cache in the comparison.

Hulunlante Worku

How I Put PgCache in Front of a 16-Million-Row Postgres Database

Independent, unpaid. Not affiliated with PgCache.

PgCache 0.6.2
Query Origin Postgres Through PgCache
Point lookup by id No gain 0.3 ms 0.3 ms
Count users by tier (1M rows) 140 ms 0.5 ms
Revenue by country (5M-row join) 1.4 s 0.5 ms
Top products per category (10M-row join) 2.9 s 0.6 ms

Setup. PostgreSQL 17, synthetic e-commerce schema: 1M users, 2K products, 5M orders, 10M order items. 150 runs per query at concurrency 10.

Method. Indexed every foreign key and every filter and group-by column first. Warmed both sides. Confirmed all 150 runs were cache hits against PgCache's own counter.

Author's caveat. Invalidation latency is unrepresentative for ~90 seconds after startup.

When PgCache won't help

These benchmarks also show where PgCache doesn't pay off. If your workload looks like one of these, expect a small gain or none.

  • Your origin already answers faster than a cache hit. In Leonardo's openFGA tests the origin served each query in about 40 µs with all its data in memory, and PgCache added about 5 µs. With more than 100 queries behind each request, that overhead added up.
  • The database is a small part of each request. On one NetBox page the database was 3% of the time, so even an instant cache couldn't make that page more than 3% faster.
  • Writes take up most of your database time. Writes pass through to origin on both paths. Mixed with 10% writes, a cheap point lookup lost its whole gain, because the writes used about three quarters of the time. An expensive dashboard read with the same 10% writes was still about 10x faster through PgCache.
  • Your reads run inside transactions. Every query between BEGIN and COMMIT passes through to origin.

Not sure where your own queries land? Run the Fit Analyzer on your workload. It runs in your browser, and nothing is uploaded.

Run your own benchmark

pgcache-bench

Ours. Built by James Nelson, PgCache CTO.

Drives two identical lanes, one straight to Postgres and one through PgCache, against the public dba.stackexchange.com dump. Reports latency, throughput and origin CPU as concurrency ramps. Page-shaped workloads with a configurable write rate. Runs under Docker Compose locally, or on RDS plus EC2 with the included OpenTofu config.

Budget 25 to 30 minutes to a first number, mostly loading the dump. Needs Docker with ~8 GB, Rust 1.85+, and 7z. Output is Prometheus metrics; warm to steady state before quoting anything.

Just want to see PgCache run? Try it in one command on a laptop with Docker.

Published a benchmark? Send it over and we will link it (even if the result is poor!). philip@pgcache.com