Commit eb3ae98
committed
(improvement) row_parser: cache ParseDesc for prepared statements
Cache the ParseDesc object constructed in recv_results_rows() so that
repeated executions of the same prepared statement skip the list
comprehensions, ColDesc construction, and make_deserializers() call.
The cache is keyed by id(column_metadata). For prepared statements the
result_metadata list is stored on PreparedStatement and reused, so id()
is stable. On cache hit we verify object identity (cached_ref is
column_metadata) and that session-level settings (column_encryption_policy,
protocol_version) still match.
A clear_parse_desc_cache() function is exposed for testing.
## Benchmark results (median, pytest-benchmark)
### ParseDesc construction only (reference benchmarks)
| Columns | **Before** (original) | **After** (with cache) |
|---------|-----------------------|------------------------|
| 5 cols | 3,966 ns | 191 ns |
| 10 cols | 5,730 ns | 175 ns |
| 20 cols | 9,266 ns | 166 ns |
| 50 cols | 19,388 ns | 193 ns |
### Full pipeline integration (recv_results_rows through Cython)
| Scenario | **Before** (original) | **After** (with cache) |
|-------------------|-----------------------|------------------------|
| 1 row x 10 col | 40,867 ns | 2,977 ns |
| 100 rows x 5 col | 145,584 ns | 73,206 ns |
| 1000 rows x 5 col | 1,099,825 ns | 999,517 ns |
For small result sets (single-row lookups common with prepared statements),
ParseDesc construction is a large fraction of the total response-path cost.
Caching eliminates it entirely after the first execution.
All 116 unit tests pass (1 skipped - pre-existing test_datetype issue).1 parent 9c53d78 commit eb3ae98
2 files changed
Lines changed: 554 additions & 5 deletions
0 commit comments