QAIL Go IPC vs pgx
Unix socket IPC matches pure Go performance
December 27, 2025
🎯 Fair Head-to-Head Comparison
237,561
QAIL IPC q/s
239,794
pgx q/s
99%
Performance Match
🚀 Key Insight: QAIL IPC daemon achieves 99% of pgx performance
despite IPC overhead (Go → JSON → Unix Socket → Rust → PostgreSQL). The
prepared statement caching in the Rust daemon compensates for the extra
hop.
Architecture Comparison
pgx (Pure Go)
Go App
↓ (direct)
pgx driver
↓ (TCP)
PostgreSQL
Zero overhead, optimized for years
QAIL IPC Daemon
Go App
↓ (Unix socket + JSON)
qail-daemon (Rust/Tokio)
↓ (TCP, pipeline_prepared_fast)
PostgreSQL
Extra hop, but prepared stmt caching!
50 Million Query Results
| Driver | Queries/sec | Total Time | Per Query |
|---|---|---|---|
| pgx (SendBatch) | 239,794 | 208.5s | 4,170ns |
| QAIL IPC (PreparedPipeline) | 237,561 | 210.5s | 4,210ns |
| Native Rust (baseline) | 355,000 | 141s | 2,817ns |
Test Configuration
| Parameter | Value |
|---|---|
| Total Queries | 50,000,000 |
| Batch Size | 10,000 queries |
| Query Type | SELECT id, name FROM harbors LIMIT $1 |
| Protocol | Prepared statement + pipeline mode |
| Connection | Single connection (no pooling) |
Evolution: From CGO to IPC Daemon
| Mode | Queries/sec | vs pgx | Notes |
|---|---|---|---|
| QAIL CGO (original) | 126,000 | 53% | CGO overhead, Go I/O |
| QAIL IPC (PipelineFast) | 42,000 | 18% | Full Query struct per batch |
| QAIL IPC (PreparedPipeline) | 237,561 | 99% | Prepared stmt caching |
Why PreparedPipeline Matches pgx
The Secret: Parse once, Bind+Execute many.
The Rust daemon caches the prepared statement after a single Prepare call. Subsequent PreparedPipeline calls only send parameter
values, not the full query structure. This eliminates the JSON overhead
for the SQL template.
┌─────────────────────────────────────────────────────────┐
│ Go Client │
├─────────────────────────────────────────────────────────┤
│ 1. Prepare("SELECT ... LIMIT $1") → handle │
│ 2. PreparedPipeline(handle, [["5"],["3"],["1"],...]) │
│ ↓ (small JSON: just params) │
├─────────────────────────────────────────────────────────┤
│ qail-daemon (Rust) │
├─────────────────────────────────────────────────────────┤
│ - Lookup cached PreparedStatement by handle │
│ - Call pipeline_prepared_fast() → Bind+Execute × 10,000 │
│ - Return count (no row parsing overhead) │
└─────────────────────────────────────────────────────────┘
Potential Optimizations (Not Yet Tuned)
| Optimization | Estimated Gain | Status |
|---|---|---|
| MessagePack instead of JSON | +10-15% | Planned |
| Pre-encoded params in Go | +5-10% | Planned |
| Connection pooling in daemon | +5% | Planned |
| Total Potential | 260K+ q/s | Could beat pgx |
Conclusion
QAIL's IPC daemon architecture proves that language-agnostic database access doesn't have to sacrifice performance. With prepared statement caching, the Rust daemon achieves 99% of pure Go pgx performance while offering:
- AST-native query building
- Cross-language consistency (Go, Python, PHP, Zig)
- QAIL's type-safe query syntax
- Single daemon serving multiple clients
🎯 Bottom Line
99%
of pgx performance
237K
queries/second
0
CGO overhead