You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[SqlStatement] Add transparent block-prefetch for classic per-row fetch loops
Classic result iteration (while(cursor.FetchRow()){ GetColumn<T>(i) },
bound output columns, SqlRowIterator<T>, SqlVariantRowCursor) issued one
SQLFetch per row -- one network round-trip per row, which dominates
wall-clock for large result sets on TCP backends. The recent row-wise
array fetch only sped up the materializing DataMapper paths (All/Range/
First); the lazy cursor loops were left on the per-row path and cannot be
rewritten across all client code.
Back the classic cursor transparently with the existing RowArrayCursor:
on the first fetch of an eligible result set the statement arms a block
buffer (SQL_ATTR_ROW_ARRAY_SIZE) and serves FetchRow()/GetColumn<T>() and
bound-column scatters from it, cutting round-trips from N to
ceil(N/depth). On by default; depth is a single connection-level knob
(SqlConnection::SetDefaultPrefetchDepth, default PrefetchDepthDefault =
1000; <= 1 disables). Capability-gated by SupportsNativeRowArrayFetch().
Eligibility is restricted to fixed-width numeric, temporal and GUID
columns, whose block reconstruction is byte-identical to the per-row
binder on every backend. Result sets carrying character/text, NUMERIC,
TIME, binary or LOB columns transparently stay on the per-row path
(faithful materialization of those is not uniform across backends: MSSQL
returns narrow text in the client codepage, SQLite's dynamic typing
reports unreliable text sizes). A new SqlLogger::OnFetchBlock hook makes
the round-trip reduction observable/testable.
Performance: round-trips drop ~1000x at depth 1000 for eligible sets;
no regression on the per-row path (no allocation when disabled/ineligible).
Risk: an active cursor reads ahead up to one block (a few MB, budget-
clamped); the connection knob is the global escape hatch.
Tested: sqlite3, mssql2022 (Docker), postgres (Docker 16.4) -- full suite
shows no regression vs the pre-change baseline; new [prefetch] suite green
on all three. Build clean under clangcl-debug (PEDANTIC /WX).
Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
0 commit comments