perf(spanner): optimize query result decoding and type resolution - #18330
Open
olavloite wants to merge 1 commit into
Open
perf(spanner): optimize query result decoding and type resolution#18330olavloite wants to merge 1 commit into
olavloite wants to merge 1 commit into
Conversation
Improve query result decoding performance in StreamedResultSet and simplify
type decoder resolution in _helpers.
* Optimize row construction in StreamedResultSet._merge_values:
- Process complete rows in batch using direct column indexing rather than
iterating cell-by-cell with repeated append() calls and boundary checks.
- For lazy decoding, slice raw values directly into rows.
- Add an explicit guard for width == 0 to prevent unbounded buffer growth
on empty schemas.
- Separate partial row boundary handling from complete row decoding by
extracting _append_to_current_row, _decode_eager_rows, and
_decode_lazy_rows, removing duplicated cell-appending logic.
* Optimize type resolution in _helpers:
- Replace the if/elif cascade in _get_type_decoder with an integer-keyed
_SCALAR_DECODERS lookup table.
- Pre-allocate static decoder callables at module scope to avoid lambda
recreation when resolving column metadata.
Contributor
There was a problem hiding this comment.
Code Review
This pull request refactors and optimizes row decoding and value merging in both synchronous and asynchronous streamed result sets, introducing batch-decoding helpers and mapping scalar type codes to a pre-defined dictionary of decoders. Reviewers suggested further performance optimizations, including removing redundant integer conversions for IntEnum keys in _get_type_decoder, and using zip with sliced lists in _append_to_current_row and _decode_eager_rows to avoid the overhead of index lookups and enumeration.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Improve query result decoding performance in StreamedResultSet and simplify type decoder resolution in _helpers.
Benchmark Results: Query Result Decoding & Type Resolution
NOTE: These benchmark results are unfortunately no longer fully valid, as they now also include the other changes that have been added to the main branch. The biggest contributor to the latency decrease in these benchmarks is not actually this change, but rather an earlier change where we got rid of the
.pop(0)calls when iterating through the rows. These benchmark results should therefore rather be seen as 'the performance compared to main is still much better', and not 'it got this much better due to this change'.We benchmarked this branch against the 7-day nightly baseline on
mainusing the automated closed-loop result set benchmarks on Google Compute Engine (n2-standard-2ineurope-north1-a). Both benchmarks measure client-side row iteration and cell deserialization latency across all rows in the query result.1. Read Narrow Result Set (2
int64columns)main7-day avg)2. Read Large Result Set (12 varied type columns)
Types: bool, bytes, date, float32, float64, interval, json, int64, numeric, string, timestamp, uuid
main7-day avg)Baseline reflects nightly runs over the preceding 7 days (2026-09-03 to 2026-09-10 UTC). PR results reflect 15-minute runs excluding initial warmup.