perf: trim per-query allocation in the statement build path#296
Merged
Conversation
Statement building dominated per-operation allocation on short operations: about 8 KB per by-id build against a 1.9 KB hand-written JDBC floor, even with the compiled SQL cached. Six changes cut the build phase in half and reduce total allocation on the short workloads by 34-40%: - Query creation uses the dialect of the template that generated the SQL instead of repeating the provider lookup on every query, which could even select a different dialect than the statement was generated with. - SqlParser strips leading whitespace before the keyword fast path (templates regularly start with a newline, which forced the comment-removal fallback on every call) and skips comment, quoted-identifier, and string-literal regex passes entirely when no marker character is present. - Named parameter validation runs in a single pass without stream and grouping machinery; positional validation uses a bit set instead of a boxed sorted set, with the boxed path kept as a cold fallback. - The unsafe-statement check, a pure function of the immutable compiled SQL, is computed once per processor instead of re-scanning on every bind. - AbstractMetamodel caches its hash code: metamodels are immutable and are hashed on every compilation-key lookup. - The query builder provider is resolved once and reused, mirroring getORMReflection(), instead of sorting the provider list on every select. Refs #294 (remaining tail: per-call binding-session and parameter carriers, and the template machinery of dynamically assembled projections).
zantvoort
force-pushed
the
perf/query-build-allocation
branch
from
July 20, 2026 18:45
33f0003 to
3ec1f3b
Compare
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.
Part of #294 (the issue stays open for the remaining tail).
What
Statement building dominated Storm's per-operation allocation on short operations: ~8 KB per by-id build against a 1.9 KB hand-written JDBC floor, even with the compiled SQL cached. JFR allocation profiling itemized the producers; six changes cut the build phase in half and reduce total allocation on the short workloads by 34–40%.
SqlParser: leading-whitespace fast path + marker-char guardsBitSetpositional checkgroupingBymachinery even for purely positional statements; a boxedTreeSetper bind (boxed path kept as cold fallback for non-positive positions, identical error messages)hasWhereClausefull-SQL regex on every bind of UPDATE/DELETE statements, despite being a pure function of the immutable compiled SQLAbstractMetamodelcaches its hash codeObjects.hashvarargs array per compilation-key lookup (String.hashCode pattern)getORMReflection()select()Measured effect
Precise per-thread allocation counters (warmed hot loop, by-id read, PostgreSQL):
JMH allocation profiler, per operation:
The excess allocation correlated with the small latency deltas on the point workloads; the wall-clock effect will show on the pinned-runner benchmark.
Notes
BindingSession/SqlImpl/parameter-list carriers and the template machinery of dynamically assembled projections (the reasondynamicmoved least).Testing
All suites green against their real databases: storm-foundation 320 · storm-core 2307 · H2 158 · SQLite 131 · PostgreSQL 178 · MySQL 175 · MariaDB 158, plus a full reactor test-compile.