perf(fivesql2): Go-native FetchRow fast path — 1.3-1.7x on agg/window
TSqlExecutor:FetchRow was the per-row workhorse for aggregation, HAVING, and window queries. Even with the pre-built aFetchCache binding columns to (nWA, nFPos), the PRG FOR loop paid one method dispatch per column per row (dbSelectArea, FieldGet, AllTrim, AAdd) — profile pinned it at ~30% of B4 CPU. SqlFetchRowFast collapses the cache-path loop into a single Go call: - bound entry: SelectByNum + area.GetValue directly - unbound (aggregate/expression): self:EvalExpr via Send - character values: TrimSpace inline The PRG FetchRow keeps its original cache-miss fallback path unchanged for rare queries where aFetchCache isn't built. Bench deltas (median of 3 steady runs, 1000 iters): B4_GROUP_HAVING 418 → 327 us -22% (1.28x) B9_ROW_NUMBER 191 → 120 us -37% (1.59x) B10_RANK_PART 228 → 135 us -41% (1.69x) B11_SUM_OVER 249 → 156 us -37% (1.60x) B14_COUNT 235 → 219 us -7% B15_CTE_WIN_JOIN 1577 → 1452 us -8% Single-table SELECT (B1-B3, B5-B7, B8) stays flat — those already hit the column-binding fast path and don't need aggregate dispatch. FiveSql2 43/43, Harbour compat 56/56. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -753,28 +753,14 @@ RETURN aCache
|
||||
METHOD FetchRow( aExprs ) CLASS TSqlExecutor
|
||||
|
||||
LOCAL aRow := {}, i, xVal
|
||||
LOCAL xE, cRef, nDot, nWA, nFPos, cField, cTblAlias, cA, aBound
|
||||
LOCAL xE, cRef, nDot, nWA, nFPos, cField, cTblAlias, cA
|
||||
|
||||
/* Fastest path: pre-bound columns (built once per join by RunSelect) */
|
||||
/* Fastest path: pre-bound columns (built once per join by RunSelect).
|
||||
* Go-native: SqlFetchRowFast collapses the per-row Harbour FOR loop
|
||||
* into a single Go call, saving ~30% of GROUP BY CPU spent in PRG
|
||||
* method dispatch. Falls back to self:EvalExpr for unbound entries. */
|
||||
IF ::aFetchCache != NIL .AND. Len( ::aFetchCache ) == Len( aExprs )
|
||||
FOR i := 1 TO Len( aExprs )
|
||||
aBound := ::aFetchCache[ i ]
|
||||
IF aBound != NIL
|
||||
dbSelectArea( aBound[ 1 ] )
|
||||
xVal := FieldGet( aBound[ 2 ] )
|
||||
IF ValType( xVal ) == "C"
|
||||
xVal := AllTrim( xVal )
|
||||
ENDIF
|
||||
AAdd( aRow, xVal )
|
||||
ELSE
|
||||
xVal := ::EvalExpr( aExprs[ i ][ 1 ] )
|
||||
IF ValType( xVal ) == "C"
|
||||
xVal := AllTrim( xVal )
|
||||
ENDIF
|
||||
AAdd( aRow, xVal )
|
||||
ENDIF
|
||||
NEXT
|
||||
RETURN aRow
|
||||
RETURN SqlFetchRowFast( Self, aExprs, ::aFetchCache )
|
||||
ENDIF
|
||||
|
||||
FOR i := 1 TO Len( aExprs )
|
||||
|
||||
Reference in New Issue
Block a user