A block of rows in one call - #29
Merged
Merged
Conversation
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.
fetchmanyonzudb.Result, and the DB-API cursor built on it.The layer had a
fetchmanyalready, and it was a loop overfetchone, so asking for a thousand rows cost a thousand crossings into the engine. Now the native result has the block form: one lock, one crossing, and the position moves once at the end, so a conversion that fails leaves the result where it was rather than half a block further on. Asking for more rows than are left gives what is left. Asking for none gives none, which is what a loop over a page size read from configuration wants. Asking for fewer than none is refused, because an empty list is exactly what the end of the rows looks like and a loop that believed it would stop early and quietly.fetchallin the DB-API layer goes through the same call now, sincelen(result)is every row the statement produced and is never fewer than the rows left.While measuring it,
fetchoneturned out to be spending most of its time on the wrapper rather than on the rows._translating()is a generator-based context manager and costs about 1.4 microseconds to enter and leave, which is nine times what reading a row costs; entering it a million times took 1.4 seconds against 155 ms for the million rows. It is written out as a try and an except infetchoneand nowhere else, since that is the one call in this layer a caller makes once per row.Over a million rows in two columns on this machine:
fetchone, beforefetchone, afterfetchmany(1000)fetchallBlocks beat
fetchalland hold a thousand tuples where it holds a million, so it is both the faster way of reading a large result and the one that does not have to fit.Nine tests, the stub, and a paragraph in the DB-API section of the README. Green locally: ruff, ruff format, clippy, cargo fmt, and the suite.