22 pages across Diataxis quadrants (start / how-to / reference / explain). Custom amber-on-charcoal theme, wire-dump hero animation, Supported Systems footer badge. caddy-docker-proxy deployment with prod + dev profiles, Makefile with prod/dev/down/logs/local targets.
49 lines
2.1 KiB
Markdown
49 lines
2.1 KiB
Markdown
---
|
||
title: Optimize bulk SELECT
|
||
description: How the buffered reader works in practice — when it's on, when it isn't, how to A/B-measure your workload.
|
||
sidebar:
|
||
order: 5
|
||
---
|
||
|
||
The connection-scoped buffered reader (Phase 39) is **enabled by default** as of `2026.05.05.12`. For most workloads you don't need to touch anything — the bulk-fetch gap against IfxPy is now ~5–15% rather than ~140%.
|
||
|
||
For the architectural rationale, see [The buffered reader →](/explain/buffered-reader/).
|
||
|
||
## Disabling the buffered reader
|
||
|
||
```bash
|
||
IFX_BUFFERED_READER=0 python my_app.py
|
||
```
|
||
|
||
The flag is read once at connection construction. To flip behavior on existing connections, close and reopen the pool.
|
||
|
||
There's no expected reason to disable it in production. The flag exists so you can A/B-measure your own workload and so we can debug regressions if they appear.
|
||
|
||
## A/B-measuring your workload
|
||
|
||
```bash
|
||
# Baseline: no buffered reader
|
||
IFX_BUFFERED_READER=0 python -m mybench
|
||
|
||
# With buffered reader
|
||
IFX_BUFFERED_READER=1 python -m mybench
|
||
```
|
||
|
||
For typical bulk-SELECT workloads expect a 30–40% wall-time reduction. For workloads dominated by single-row queries the impact is small (small queries are RTT-bound, not framing-bound).
|
||
|
||
## When the speedup is largest
|
||
|
||
Workloads where every column read makes ~4–5 small `recv()` calls — i.e. tabular data, narrow rows, large row counts. The buffered reader replaces N small `recv()` calls with one `recv(64K)` per ~64 KB of incoming data.
|
||
|
||
| Workload shape | Speedup |
|
||
|---|---:|
|
||
| Wide row, single fetch (1 row × 100 cols) | minimal |
|
||
| Narrow row, large fetch (100k rows × 5 cols) | 30–40% |
|
||
| `executemany` response drain (1k inserts) | 25–30% |
|
||
|
||
## Memory profile
|
||
|
||
The buffer is per-connection, sized to grow up to the largest single PDU it sees. Typical steady-state: 64 KB to a few hundred KB per connection. The buffer is freed when the connection closes; for long-lived pool connections it's amortized.
|
||
|
||
If you're running 10,000 connections at idle, the buffer cost is ~1–2 GB across the fleet. For typical pool sizes (10–50 connections) it's ~1–10 MB total.
|