perf(fivesql2): extend WA cache to SELECT path — 2x faster single-table

TSqlExecutor:OpenTable now hands lifetime to the WA cache for stable
aliases (user-supplied or table-named). CloseOpened skips those
entries, so the DBF mmap stays alive across queries instead of being
unmapped + re-opened 1000 times a bench. Previously the WA cache only
covered DML (INSERT/UPDATE/DELETE) — SELECT was still paying the full
dbUseArea/dbCloseArea syscall bill every query (profile showed
rtlDbCloseArea + munmap at ~30% of total CPU).

AcquireTemp-generated aliases (FA_####) are excluded — they change
every query (self-joins, nested depth), so caching them would just
leak entries for no reuse. JOIN / recursive CTE regressions from an
earlier unrestricted version are gone.

Bench deltas vs prior HEAD (median of 3 steady runs, 1000 iters):
  B1_SELECT_STAR   82 → 41 us   -50%  (2.0x)
  B2_WHERE_FILTER  78 → 35 us   -55%  (2.2x)
  B3_ORDER_BY      90 → 48 us   -47%  (1.88x)
  B5_DISTINCT      75 → 32 us   -57%  (2.34x)
  B7_CTE_SIMPLE   120 → 77 us   -36%  (1.56x)
  B9_ROW_NUMBER   239 → 194 us  -19%
  B10_RANK_PART   276 → 233 us  -16%
  B11_SUM_OVER    296 → 252 us  -15%
  B4_GROUP_HAVING 498 → 450 us  -10%
Others flat (JOIN / recursive CTE / DML already covered).

FiveSql2 43/43, Harbour compat 56/56.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 13:20:46 +09:00
parent 6974ff9473
commit f27c96c7f0

View File

@@ -202,7 +202,18 @@ METHOD OpenTable( cTable, cAlias ) CLASS TSqlExecutor
nWA := ::oIndex:OpenTable( cTable, cAlias, .T., .T. )
IF nWA > 0
AAdd( ::aOpened, cAlias )
/* When the WA cache is on, hand lifetime to the cache so CloseOpened
* leaves the mmap alive for the next query. Profile showed
* rtlDbCloseArea + munmap at ~30% of SELECT CPU prior to this branch.
*
* Skip caching when the alias is an AcquireTemp-generated "FA_####"
* token: those change every query (self-joins, nested depth), so
* caching them just leaks entries while delivering zero reuse. */
IF SqlWACacheIsEnabled() .AND. ! ( Left( cAlias, 3 ) == "FA_" )
SqlWACachePut( cAlias, nWA )
ELSE
AAdd( ::aOpened, cAlias )
ENDIF
/* Register with alias manager if not already tracked */
lFound := .F.
FOR i := 1 TO Len( ::oAlias:aSlots )