Tuning note: why the query has an ORDER BY
Tuning note: why the query has an ORDER BY
The first query shape was a pure aggregate with no sort:
SELECT COUNT(*), AVG(val) FROM reads_test
WHERE id BETWEEN %s AND %s AND val >= %s
with SCAN_W = 25000 rows (single-query p50 ~2.85 ms, in the 1-3 ms band).
That shape reproduced the p99 explosion cleanly (p99 ~4 ms at the peak vs ~1490 ms at C=512, ~33x), but the QPS knee was soft and, more importantly, the pool did not beat direct-512 on throughput:
Exp A peak : 909 QPS @ C=8, p99 45.4 ms
Exp A C=512 : 780 QPS, p99 1490 ms (only 1.17x QPS drop from peak)
Exp C best pool : 749 QPS @ P=8, p99 47.2 ms (0.96x the QPS of direct-512)
A pure CPU-bound scan+aggregate lets MySQL 8.0 hold throughput near core-saturation even at 512 connections (it just queues internally), so the only thing that collapsed was latency, not QPS. The pool’s win was entirely in the tail — it did not “recover throughput,” because throughput had barely dropped.
Fix (what was tuned): switched to a query that also does a real filesort
over the non-indexed val column, so each connection allocates a sort buffer and
burns extra CPU:
SELECT id, val FROM reads_test
WHERE id BETWEEN %s AND %s AND val >= %s
ORDER BY val DESC LIMIT 50
with SCAN_W = 20000 and a low val threshold so nearly every scanned row feeds
the sort. Single-query p50 stayed ~2.6 ms (still in band). Now the throughput
knee is real: peak 1137 QPS @ C=4 falls to 720 QPS @ C=512 (1.58x drop), and the
pool of 8 backend connections serving 512 clients delivers 957 QPS — 1.33x the
QPS of direct-512 at 41x lower p99 — recovering 84% of peak. That is the
result checked into ../.
Both shapes are real captured runs; only the sort-heavy one is kept as the headline because it shows the throughput collapse the pool actually reverses.