Skip to content

perf(keywords): allocation-free case-insensitive keyword lookups [W2-07] - #944

Open
ajitpratap0 wants to merge 2 commits into
mainfrom
perf/w2-07-alloc-free-keywords-api
Open

ajitpratap0 wants to merge 2 commits into
mainfrom
perf/w2-07-alloc-free-keywords-api

Conversation

@ajitpratap0

Copy link
Copy Markdown
Owner

Summary

  • New lookupFold helper (pkg/sql/keywords/lookup_fold.go): upper-cases pure-ASCII words up to 64 bytes into a stack buffer and looks up from there; any other input falls back to strings.ToUpper. Used by IsKeyword, GetKeywordType, IsReserved, GetKeyword, GetTokenType, IsCompoundKeywordStart and containsKeyword. Results are identical for every input (Unicode folds such as ſelect, invalid UTF-8, long words, case-sensitive instances).
  • Adds BenchmarkKeywordLookup (commit 1 = baseline) and tests: differential oracle vs frozen copies of the old bodies, fuzz target, built-in-keys-fit-fast-path check, zero-alloc test (fails on the old code; 7 mutations M1-M7 each caught).
  • Consumers (formatter render, highlighter) see ~no change: their corpora already spell names in upper case. The gain shows on the direct benchmark.

Test Plan

  • task test:cbinding, go test ./pkg/compatibility/..., staticcheck on ./pkg/sql/keywords/...: pass.
  • go test -race on keywords, formatter, highlight, mcp: pass. task check hit 120s package timeouts (formatter, transpiler) at machine load average 50-75; both pass when run alone with a larger timeout.
  • Fuzz 60s: pass (69k execs). Inlining: can inline lookupFold[...], string(buf[:len(s)]) does not escape.
  • Local task bench:ab BASE=<commit1> (20 layouts, indicative, shared M4): geomean -54.5%; lower/mixed/miss -63% to -76% for all six methods, allocs 1 -> 0, B/op -> 0; upper -6% to -29%; long (65 B) ~0 except IsKeyword/long +4.75% (p=0.007, 3% spread, low power; allocs unchanged, code path unchanged for len>64 so I read it as noise).
  • CI perf gate: see comment below (filled after run).

Breaking Changes

None.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DnbRnTFErhoMJdAjVEeCg2

ajitpratap0 and others added 2 commits November 3, 2026 22:40
lookupFold upper-cases pure-ASCII words up to 64 bytes into a stack buffer;
other input falls back to strings.ToUpper. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DnbRnTFErhoMJdAjVEeCg2
@vercel

vercel Bot commented Nov 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gosqlx-website Ready Ready Preview Nov 3, 2026 5:18pm UTC

@github-actions github-actions Bot added documentation Improvements or additions to documentation performance dialects labels Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 20s —— View job


Review of PR #944: allocation-free keyword lookups

Verdict: looks good, with a few nits. I found no blocking issues.

I read the production diff in full. I did not run the tests or benchmarks. The numbers below are from your PR description.

Correctness

  • lookupFold (pkg/sql/keywords/lookup_fold.go) matches strings.ToUpper for every input class.
    • A pure-ASCII word of 64 bytes or fewer is upper-cased into a stack buffer.
    • Any byte at or above utf8.RuneSelf breaks out of the loop and falls back to strings.ToUpper. That covers ſ→S, ı→I and invalid UTF-8.
    • Words over 64 bytes also fall back.
    • The i == len(s) check after the loop is correct, including for the empty string.
  • m[string(buf[:n])] is the map-index form the compiler optimises to avoid allocating. Your escape-analysis note confirms it.
  • The case-sensitive paths are unchanged. GetKeyword still upper-cases unconditionally, as before, regardless of ignoreCase.
  • GetKeywordType and GetTokenType now return TokenTypeWord explicitly on a miss in the folded branch. That is equivalent to the old behaviour.
  • A generic helper with V any should be fine here. Keyword is a small struct, so copying it by value is cheap.

Performance

  • The 64-byte buffer is zero-initialised on every call. For typical 3–10 byte keywords that is a small fixed cost (about one 64-byte store). It is still far cheaper than an allocation, and the "upper" case still improves by 6–29%.
  • The IsKeyword/long +4.75% result (p=0.007) is almost certainly noise or layout effects. The len > 64 path is the same code as before, except for the extra length compare. I agree with your reading.

Tests

  • The differential oracle against frozen copies of the old bodies, the fuzz target, the "built-in keys fit" pin and the zero-alloc test are the right set. The mutation checks (M1–M7) are a nice touch.
  • One suggestion: add explicit cases at exactly 63, 64 and 65 bytes if they are not already there. That is where the <= boundary could regress. Skip this if the oracle already generates them.

Nits

  • In categories.go, the new line "Pure-ASCII words up to 64 bytes…" sits directly under the first doc line of GetKeywordType. The comment is a single run-on paragraph with no sentence break, so consider separating it with a // blank line.
  • keyBufLen's comment says "longest is 20 bytes on origin/main". That will go stale as keywords are added. The pinning test already enforces the invariant, so the number could be dropped.
  • CHANGELOG, README and doc.go are updated. The PR description's "CI perf gate" comment is still to be filled in. Please make sure the amd64 gate result is posted before merge, as CLAUDE.md requires.

No security concerns. The change is pure lookup logic with no new inputs or unsafe code.
· branch perf/w2-07-alloc-free-keywords-api

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

Perf gate: PASS (shadow mode: report only, this check never fails)

Base a72ec74daf9a, head 57e8705a9ef4. 20 interleaved rounds, 20 randomized code layouts per arm (-randlayout seeds 416829694442..416829694461; A/A' 416829694462..416829694481), benchtime 100ms, -cpu 1, GOMEMLIMIT 64MiB, pinned to CPU 3 (SMT siblings 2-3) with taskset.

Runner CPU: AMD EPYC 7763 64-Core Processor (x86_64). Base and head ran interleaved in this job, so the tables show their ratios only; absolute timings (raw files in the artifact) hold for this CPU and this job alone and are never compared across jobs.

  • no gated metric moved past its threshold

Rules: each arm runs 20 randomized code layouts (-ldflags=-randlayout); time regresses at >= +3% when significant at a false discovery rate of 0.01 over the suite (Benjamini-Hochberg on exact Mann-Whitney U p-values of the per-layout medians, so a regression must hold across layouts, not within one binary), or a suite geomean >= +1.5% (per-layout suite geomeans, same test); allocs/op must not increase; B/op must not rise more than 2%; instructions/op must not rise more than 1.5%. The A/A' control runs the base revision under a disjoint set of layout seeds; when more than 10% of benchmarks move over 3% in it, the run is noisy: re-run once, then inconclusive (neutral).

Gated suite (GOGC=off, GOMAXPROCS=1)

benchmark time p A/A' spread B/op allocs/op status
ParseE2E/simple_select +0.06% 0.903 +0.41% 2.01% +0.00% 5 → 5 ok
ParseE2E/select_where +0.80% 0.081 +0.19% 1.09% +0.00% 18 → 18 ok
ParseE2E/join -0.02% 0.978 -0.25% 0.69% +0.00% 17 → 17 ok
ParseE2E/aggregate -0.47% 0.512 -0.80% 3.04% +0.00% 18 → 18 ok
ParseE2E/subquery +0.21% 0.850 -0.88% 1.88% +0.00% 14 → 14 ok
ParseE2E/cte -0.38% 0.565 +0.29% 2.06% +0.00% 21 → 21 ok
ParseE2E/window +0.18% 0.552 -0.02% 1.09% +0.00% 11 → 11 ok
ParseE2E/complex -0.65% 0.330 -0.42% 2.31% +0.00% 49 → 49 ok
ParseE2E/insert +0.47% 0.357 +0.30% 1.25% +0.00% 17 → 17 ok
ParseE2E/update +0.53% 0.228 +0.19% 0.90% +0.00% 13 → 13 ok
ParseE2E/delete +0.50% 0.386 -0.25% 1.17% +0.00% 5 → 5 ok
ParseRW/postgresql/medium +0.63% 0.383 +0.70% 1.83% +0.00% 646 → 646 ok
ParseRW/mysql/medium +0.35% 0.383 +0.36% 1.32% +0.00% 368 → 368 ok
ParseRW/mariadb/medium +0.25% 0.461 +0.34% 1.26% +0.00% 528 → 528 ok
ParseRW/sqlserver/medium -0.25% 0.512 +0.60% 1.05% +0.00% 927 → 927 ok
ParseRW/oracle/medium +0.16% 0.583 +0.25% 0.94% +0.00% 1090 → 1090 ok
ParseRW/sqlite/medium +0.35% 0.398 +0.63% 1.41% +0.00% 347 → 347 ok
ParseRW/snowflake/medium +0.34% 0.461 +0.24% 0.96% +0.00% 776 → 776 ok
ParseRW/clickhouse/medium -1.78% 0.142 -1.86% 2.54% +0.00% 383 → 383 ok
ParseFresh/simple_select -0.19% 0.636 +0.35% 1.75% +0.00% 6 → 6 ok
ParseFresh/join +0.21% 0.646 +0.47% 1.26% +0.00% 18 → 18 ok
ParseFresh/complex +0.38% 0.561 +0.08% 1.93% +0.00% 50 → 50 ok
PoolGetPut/serial -0.45% 0.394 -0.73% 1.76% +0.00% 0 → 0 ok
Tokenize/scratch/join +0.03% 0.978 +2.04% 1.94% +0.00% 0 → 0 ok
Tokenize/scratch/complex +0.10% 0.892 +2.45% 1.76% +0.00% 0 → 0 ok
Tokenize/scratch/insert +0.80% 0.640 +2.12% 2.21% +0.00% 0 → 0 ok
Normalize/simple_select -0.07% 0.892 +0.11% 1.14% +0.00% 7 → 7 ok
Normalize/join -0.22% 0.675 +0.11% 1.52% +0.00% 23 → 23 ok
Normalize/complex -0.15% 0.685 +0.27% 1.38% +0.00% 68 → 68 ok
TransformParse/simple_select +0.47% 0.317 -0.20% 1.37% +0.00% 5 → 5 ok
TransformParse/join -0.60% 0.218 -0.85% 1.40% +0.00% 17 → 17 ok
TransformParse/complex +0.78% 0.429 -1.51% 1.60% +0.00% 49 → 49 ok
LintParallel/rules +0.43% 0.265 -0.00% 0.54% +0.00% 229686 → 229686 ok
LintParallel/lint +0.22% 0.659 +0.05% 1.49% +0.00% 308264 → 308265 ok
LintRW/postgresql -0.59% 0.478 -0.46% 2.91% -0.00% 34190 → 34189 ok
LintRW/mysql +0.35% 0.602 -0.13% 1.60% +0.00% 41490 → 41490 ok
LintRW/mariadb +0.73% 0.301 +0.42% 2.45% -0.00% 38235 → 38235 ok
LintRW/sqlserver +1.04% 0.063 +0.27% 1.08% -0.00% 34620 → 34620 ok
LintRW/oracle +0.11% 0.883 +0.03% 1.79% -0.00% 42243 → 42243 ok
LintRW/sqlite -0.34% 0.565 -1.22% 1.94% +0.00% 37576 → 37576 ok
LintRW/snowflake +0.54% 0.659 +0.77% 4.44% +0.00% 37559 → 37559 ok
LintRW/clickhouse +0.63% 0.565 +0.85% 5.14% +0.00% 42343 → 42343 ok
LintRule/L007 +0.37% 0.738 +0.20% 3.67% +0.00% 72565 → 72565 ok
LintRule/L010 +0.43% 0.018 +0.07% 0.91% +0.00% 0 → 0 ok
ParseError/syntax_mid/parse -0.02% 0.946 -0.50% 0.85% +0.00% 12 → 12 ok
ParseError/syntax_mid/validate +0.09% 0.797 -0.43% 1.53% +0.00% 12 → 12 ok
ParseError/syntax_end/parse -0.37% 0.543 -0.67% 3.30% +0.00% 16 → 16 ok
ParseError/syntax_end/validate +0.58% 0.044 +0.08% 0.74% +0.00% 16 → 16 ok
ParseError/tokenize/parse +0.03% 0.925 -0.85% 1.16% +0.00% 4 → 4 ok
ParseError/tokenize/validate +0.18% 0.797 -0.45% 1.66% +0.00% 21 → 21 ok
ParseError/long_prefix/parse +0.47% 0.327 -0.22% 2.19% +0.00% 219 → 219 ok
ParseError/long_prefix/validate +0.60% 0.461 -0.49% 2.02% +0.00% 219 → 219 ok
geomean +0.15% 0.355 +0.04%

time and A/A' are Hodges-Lehmann shifts over the per-layout medians. spread: the base arm's robust standard deviation across its layouts (1.4826 x MAD, relative), i.e. how much this benchmark moves between builds that differ only in function placement, plus run-to-run noise; a change much smaller than it cannot be resolved in one run.

A/A' control (base revision, disjoint layout seeds): 0 of 52 benchmarks moved more than 3%; 0 would have been flagged by the time rule; suite geomean +0.04%, p 0.738.

Low power

3 benchmark(s) have under 80% estimated power to be flagged on their own for a +5% slowdown (their spread across layouts is too wide for 20 layouts at the Benjamini-Hochberg level alpha/m = 0.000192). A slowdown below the last column usually goes unflagged there; instructions/op, allocs/op and the suite geomean still guard them.

benchmark spread power at +5% slowdown caught 80% of the time
LintRW/clickhouse 5.14% 21% +7.9%
LintRW/snowflake 4.44% 37% +6.8%
LintRule/L007 3.67% 65% +5.6%

Power is estimated with the normal approximation for the U test (Noether): power = Phi(ln(1+shift)/s * sqrt(K/2) * sqrt(3/pi) - z(1 - alpha/(2m))), with s the spread and K the layouts per arm.

Instructions per operation (cmd/perfdriver)

case instructions/op status
e2e/aggregate +0.01% ok
e2e/complex +0.01% ok
e2e/cte +0.03% ok
e2e/delete +0.05% ok
e2e/insert -0.06% ok
e2e/join +0.01% ok
e2e/select_where -0.01% ok
e2e/simple_select -0.04% ok
e2e/subquery +0.00% ok
e2e/update -0.07% ok
e2e/window +0.02% ok
rw/postgresql/medium -0.08% ok
Secondary metric: default GC, GOMAXPROCS=1 (informational)
benchmark time p
ParseE2E/simple_select -0.06% 0.850
ParseE2E/select_where +0.33% 0.596
ParseE2E/join +0.02% 1.000
ParseE2E/aggregate +0.54% 0.449
ParseE2E/subquery +0.20% 0.739
ParseE2E/cte -0.49% 0.226
ParseE2E/window +0.69% 0.450
ParseE2E/complex +0.11% 0.853
ParseE2E/insert +0.55% 0.436
ParseE2E/update +1.44% 0.143
ParseE2E/delete +0.80% 0.545
ParseRW/postgresql/medium +0.17% 0.971
ParseRW/mysql/medium +0.69% 0.436
ParseRW/mariadb/medium -0.27% 0.739
ParseRW/sqlserver/medium -1.39% 0.143
ParseRW/oracle/medium -0.56% 0.579
ParseRW/sqlite/medium +0.03% 0.971
ParseRW/snowflake/medium -0.25% 0.579
ParseRW/clickhouse/medium +0.21% 0.853
ParseFresh/simple_select -0.44% 0.631
ParseFresh/join +0.01% 0.970
ParseFresh/complex -0.32% 0.684
PoolGetPut/serial +1.46% 0.052
Tokenize/scratch/join -0.04% 1.000
Tokenize/scratch/complex +0.37% 0.739
Tokenize/scratch/insert +1.67% 0.393
Normalize/simple_select +0.22% 0.880
Normalize/join -0.64% 0.579
Normalize/complex -0.88% 0.529
TransformParse/simple_select +0.09% 0.910
TransformParse/join -0.33% 0.880
TransformParse/complex +0.28% 0.853
LintParallel/rules +0.16% 0.912
LintParallel/lint -0.57% 0.393
LintRW/postgresql -0.49% 0.393
LintRW/mysql -0.83% 0.315
LintRW/mariadb -0.17% 0.579
LintRW/sqlserver -0.08% 0.796
LintRW/oracle -0.42% 0.579
LintRW/sqlite -0.36% 0.853
LintRW/snowflake +0.01% 1.000
LintRW/clickhouse +0.56% 0.579
LintRule/L007 +0.42% 0.481
LintRule/L010 +0.08% 0.853
ParseError/syntax_mid/parse +1.12% 0.344
ParseError/syntax_mid/validate -0.07% 0.910
ParseError/syntax_end/parse -0.02% 1.000
ParseError/syntax_end/validate +0.09% 0.820
ParseError/tokenize/parse -0.60% 0.496
ParseError/tokenize/validate -0.36% 0.791
ParseError/long_prefix/parse +0.54% 0.684
ParseError/long_prefix/validate +0.29% 0.853
geomean +0.07%
Environment
date:        2026-11-03T17:38:00Z
base:        a72ec74daf9a3bd7ca53e7642ff407795df5525d
head:        working tree of 57e8705a9ef43b6ffcae9ed4ebe62ee1f559fc4e
cpu model:   AMD EPYC 7763 64-Core Processor (x86_64)
go:          go version go1.26.9 linux/amd64
kernel:      Linux 7.0.0-1017-azure x86_64
layouts:     20 per arm, -ldflags=-randlayout seeds 416829694442..416829694461 (base, head), 416829694462..416829694481 (A/A')
pinning:     pinned to CPU 3 (SMT siblings 2-3) with taskset
gcoff env:   GOGC=off GOMEMLIMIT=64MiB
clocksource: tsc
load:        7.93, 3.01, 1.11
instr count: cachegrind
perf probe:  Error: No supported events found. The instructions:u event is not supported. 

Architecture:                            x86_64
CPU(s):                                  4
Model name:                              AMD EPYC 7763 64-Core Processor
Thread(s) per core:                      2
Core(s) per socket:                      2
Socket(s):                               1
Hypervisor vendor:                       Microsoft
L1d cache:                               64 KiB (2 instances)
L1i cache:                               64 KiB (2 instances)
L2 cache:                                1 MiB (2 instances)
L3 cache:                                32 MiB (1 instance)
benchstat (primary metric, samples pooled across layouts: informational, the verdict uses the per-layout test)
goos: linux
goarch: amd64
pkg: github.com/ajitpratap0/GoSQLX/pkg/fingerprint
cpu: AMD EPYC 7763 64-Core Processor                
                        │    base     │                head                │
                        │   sec/op    │   sec/op     vs base               │
Normalize/simple_select   2.282µ ± 1%   2.283µ ± 1%       ~ (p=0.888 n=20)
Normalize/join            7.121µ ± 1%   7.082µ ± 1%       ~ (p=0.678 n=20)
Normalize/complex         19.51µ ± 1%   19.43µ ± 1%       ~ (p=0.683 n=20)
geomean                   6.818µ        6.798µ       -0.28%

                        │     base     │                 head                  │
                        │     B/op     │     B/op      vs base                 │
Normalize/simple_select     896.0 ± 0%     896.0 ± 0%       ~ (p=1.000 n=20) ¹
Normalize/join            2.211Ki ± 0%   2.211Ki ± 0%       ~ (p=1.000 n=20) ¹
Normalize/complex         6.117Ki ± 0%   6.117Ki ± 0%       ~ (p=1.000 n=20) ¹
geomean                   2.279Ki        2.279Ki       +0.00%
¹ all samples are equal

                        │    base    │                head                 │
                        │ allocs/op  │ allocs/op   vs base                 │
Normalize/simple_select   7.000 ± 0%   7.000 ± 0%       ~ (p=1.000 n=20) ¹
Normalize/join            23.00 ± 0%   23.00 ± 0%       ~ (p=1.000 n=20) ¹
Normalize/complex         68.00 ± 0%   68.00 ± 0%       ~ (p=1.000 n=20) ¹
geomean                   22.20        22.20       +0.00%
¹ all samples are equal

pkg: github.com/ajitpratap0/GoSQLX/pkg/gosqlx
                                │    base     │                head                │
                                │   sec/op    │   sec/op     vs base               │
ParseE2E/simple_select            1.586µ ± 2%   1.585µ ± 5%       ~ (p=0.899 n=20)
ParseE2E/select_where             3.415µ ± 1%   3.458µ ± 1%       ~ (p=0.080 n=20)
ParseE2E/join                     4.607µ ± 1%   4.600µ ± 1%       ~ (p=0.973 n=20)
ParseE2E/aggregate                3.459µ ± 3%   3.450µ ± 2%       ~ (p=0.512 n=20)
ParseE2E/subquery                 3.036µ ± 2%   3.048µ ± 2%       ~ (p=0.847 n=20)
ParseE2E/cte                      4.394µ ± 2%   4.349µ ± 1%       ~ (p=0.565 n=20)
ParseE2E/window                   2.863µ ± 1%   2.865µ ± 1%       ~ (p=0.551 n=20)
ParseE2E/complex                  12.11µ ± 2%   12.05µ ± 1%       ~ (p=0.331 n=20)
ParseE2E/insert                   2.131µ ± 1%   2.143µ ± 1%       ~ (p=0.358 n=20)
ParseE2E/update                   1.892µ ± 1%   1.906µ ± 1%       ~ (p=0.229 n=20)
ParseE2E/delete                   1.204µ ± 1%   1.210µ ± 1%       ~ (p=0.387 n=20)
ParseRW/postgresql/medium         166.9µ ± 1%   167.5µ ± 1%       ~ (p=0.383 n=20)
ParseRW/mysql/medium              96.08µ ± 1%   96.37µ ± 1%       ~ (p=0.383 n=20)
ParseRW/mariadb/medium            136.9µ ± 1%   137.2µ ± 0%       ~ (p=0.461 n=20)
ParseRW/sqlserver/medium          273.0µ ± 1%   272.4µ ± 1%       ~ (p=0.512 n=20)
ParseRW/oracle/medium             324.6µ ± 1%   324.7µ ± 1%       ~ (p=0.583 n=20)
ParseRW/sqlite/medium             72.25µ ± 2%   72.47µ ± 3%       ~ (p=0.398 n=20)
ParseRW/snowflake/medium          188.8µ ± 1%   189.8µ ± 1%       ~ (p=0.461 n=20)
ParseRW/clickhouse/medium         92.02µ ± 3%   88.95µ ± 3%       ~ (p=0.142 n=20)
ParseFresh/simple_select          6.998µ ± 1%   6.983µ ± 1%       ~ (p=0.635 n=20)
ParseFresh/join                   11.26µ ± 1%   11.30µ ± 1%       ~ (p=0.645 n=20)
ParseFresh/complex                20.39µ ± 2%   20.38µ ± 1%       ~ (p=0.560 n=20)
PoolGetPut/serial                 67.42n ± 3%   67.15n ± 2%       ~ (p=0.394 n=20)
ParseError/syntax_mid/parse       2.366µ ± 1%   2.365µ ± 0%       ~ (p=0.941 n=20)
ParseError/syntax_mid/validate    2.131µ ± 1%   2.133µ ± 1%       ~ (p=0.794 n=20)
ParseError/syntax_end/parse       2.654µ ± 3%   2.632µ ± 2%       ~ (p=0.542 n=20)
ParseError/syntax_end/validate    2.591µ ± 1%   2.605µ ± 1%       ~ (p=0.042 n=20)
ParseError/tokenize/parse         897.6n ± 0%   897.0n ± 1%       ~ (p=0.920 n=20)
ParseError/tokenize/validate      2.773µ ± 1%   2.772µ ± 2%       ~ (p=0.794 n=20)
ParseError/long_prefix/parse      60.16µ ± 1%   60.36µ ± 1%       ~ (p=0.327 n=20)
ParseError/long_prefix/validate   57.33µ ± 1%   57.33µ ± 2%       ~ (p=0.461 n=20)
geomean                           9.411µ        9.410µ       -0.02%

                                │     base     │                head                 │
                                │     B/s      │     B/s       vs base               │
ParseE2E/simple_select            15.64Mi ± 2%   15.65Mi ± 5%       ~ (p=0.899 n=20)
ParseE2E/select_where             28.77Mi ± 1%   28.41Mi ± 1%       ~ (p=0.082 n=20)
ParseE2E/join                     26.09Mi ± 1%   26.13Mi ± 1%       ~ (p=0.963 n=20)
ParseE2E/aggregate                23.16Mi ± 3%   23.22Mi ± 2%       ~ (p=0.512 n=20)
ParseE2E/subquery                 25.76Mi ± 2%   25.66Mi ± 2%       ~ (p=0.846 n=20)
ParseE2E/cte                      26.91Mi ± 2%   27.19Mi ± 1%       ~ (p=0.570 n=20)
ParseE2E/window                   31.32Mi ± 1%   31.29Mi ± 1%       ~ (p=0.533 n=20)
ParseE2E/complex                  29.77Mi ± 2%   29.91Mi ± 1%       ~ (p=0.358 n=20)
ParseE2E/insert                   34.01Mi ± 1%   33.82Mi ± 1%       ~ (p=0.365 n=20)
ParseE2E/update                   27.72Mi ± 1%   27.51Mi ± 1%       ~ (p=0.234 n=20)
ParseE2E/delete                   41.21Mi ± 1%   40.98Mi ± 1%       ~ (p=0.394 n=20)
ParseRW/postgresql/medium         21.50Mi ± 1%   21.42Mi ± 1%       ~ (p=0.387 n=20)
ParseRW/mysql/medium              28.17Mi ± 1%   28.09Mi ± 1%       ~ (p=0.380 n=20)
ParseRW/mariadb/medium            25.89Mi ± 1%   25.84Mi ± 0%       ~ (p=0.457 n=20)
ParseRW/sqlserver/medium          24.38Mi ± 1%   24.42Mi ± 1%       ~ (p=0.542 n=20)
ParseRW/oracle/medium             25.83Mi ± 1%   25.82Mi ± 1%       ~ (p=0.597 n=20)
ParseRW/sqlite/medium             28.59Mi ± 2%   28.51Mi ± 3%       ~ (p=0.380 n=20)
ParseRW/snowflake/medium          26.93Mi ± 1%   26.79Mi ± 1%       ~ (p=0.465 n=20)
ParseRW/clickhouse/medium         24.49Mi ± 4%   25.33Mi ± 3%       ~ (p=0.140 n=20)
ParseError/syntax_mid/parse       19.35Mi ± 1%   19.36Mi ± 0%       ~ (p=0.931 n=20)
ParseError/syntax_mid/validate    21.48Mi ± 1%   21.47Mi ± 1%       ~ (p=0.815 n=20)
ParseError/syntax_end/parse       14.01Mi ± 3%   14.13Mi ± 2%       ~ (p=0.551 n=20)
ParseError/syntax_end/validate    14.35Mi ± 1%   14.28Mi ± 1%       ~ (p=0.035 n=20)
ParseError/tokenize/parse         48.87Mi ± 0%   48.90Mi ± 1%       ~ (p=0.931 n=20)
ParseError/tokenize/validate      15.82Mi ± 1%   15.82Mi ± 2%       ~ (p=0.774 n=20)
ParseError/long_prefix/parse      38.39Mi ± 1%   38.27Mi ± 1%       ~ (p=0.317 n=20)
ParseError/long_prefix/validate   40.29Mi ± 1%   40.29Mi ± 2%       ~ (p=0.449 n=20)
geomean                           25.78Mi        25.78Mi       +0.01%

                                │      base      │                 head                  │
                                │      B/op      │     B/op      vs base                 │
ParseE2E/simple_select              816.0 ± 0%       816.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/select_where             1.523Ki ± 0%     1.523Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/join                     1.836Ki ± 0%     1.836Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/aggregate                1.812Ki ± 0%     1.812Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/subquery                 1.828Ki ± 0%     1.828Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/cte                      2.336Ki ± 0%     2.336Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/window                   1.281Ki ± 0%     1.281Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/complex                  5.025Ki ± 0%     5.025Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/insert                     824.0 ± 0%       824.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/update                     736.0 ± 0%       736.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/delete                     400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/postgresql/medium         65.91Ki ± 0%     65.91Ki ± 0%       ~ (p=0.332 n=20)
ParseRW/mysql/medium              42.37Ki ± 0%     42.37Ki ± 0%       ~ (p=0.626 n=20)
ParseRW/mariadb/medium            60.61Ki ± 0%     60.61Ki ± 0%       ~ (p=0.420 n=20)
ParseRW/sqlserver/medium          83.68Ki ± 0%     83.68Ki ± 0%       ~ (p=1.000 n=20)
ParseRW/oracle/medium             104.8Ki ± 0%     104.8Ki ± 0%       ~ (p=0.145 n=20)
ParseRW/sqlite/medium             38.12Ki ± 0%     38.12Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/snowflake/medium          77.63Ki ± 0%     77.63Ki ± 0%       ~ (p=0.451 n=20)
ParseRW/clickhouse/medium         34.82Ki ± 0%     34.82Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/simple_select            896.0 ± 0%       896.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/join                   1.914Ki ± 0%     1.914Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/complex                5.102Ki ± 0%     5.102Ki ± 0%       ~ (p=1.000 n=20) ¹
PoolGetPut/serial                   0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/parse         680.0 ± 0%       680.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/validate      680.0 ± 0%       680.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/parse       1.430Ki ± 0%     1.430Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/validate    1.430Ki ± 0%     1.430Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/parse           272.0 ± 0%       272.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/validate      1.758Ki ± 0%     1.758Ki ± 0%       ~ (p=1.000 n=20) ¹
ParseError/long_prefix/parse      22.75Ki ± 0%     22.75Ki ± 0%       ~ (p=0.996 n=20)
ParseError/long_prefix/validate   22.68Ki ± 0%     22.68Ki ± 0%       ~ (p=1.000 n=20) ¹
geomean                                        ²                 +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                │     base      │                 head                 │
                                │   allocs/op   │  allocs/op   vs base                 │
ParseE2E/simple_select             5.000 ± 0%      5.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/select_where              18.00 ± 0%      18.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/join                      17.00 ± 0%      17.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/aggregate                 18.00 ± 0%      18.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/subquery                  14.00 ± 0%      14.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/cte                       21.00 ± 0%      21.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/window                    11.00 ± 0%      11.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/complex                   49.00 ± 0%      49.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/insert                    17.00 ± 0%      17.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/update                    13.00 ± 0%      13.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseE2E/delete                    5.000 ± 0%      5.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/postgresql/medium          646.0 ± 0%      646.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/mysql/medium               368.0 ± 0%      368.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/mariadb/medium             528.0 ± 0%      528.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/sqlserver/medium           927.0 ± 0%      927.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/oracle/medium             1.090k ± 0%     1.090k ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/sqlite/medium              347.0 ± 0%      347.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/snowflake/medium           776.0 ± 0%      776.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseRW/clickhouse/medium          383.0 ± 0%      383.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/simple_select           6.000 ± 0%      6.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/join                    18.00 ± 0%      18.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseFresh/complex                 50.00 ± 0%      50.00 ± 0%       ~ (p=1.000 n=20) ¹
PoolGetPut/serial                  0.000 ± 0%      0.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/parse        12.00 ± 0%      12.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_mid/validate     12.00 ± 0%      12.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/parse        16.00 ± 0%      16.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/syntax_end/validate     16.00 ± 0%      16.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/parse          4.000 ± 0%      4.000 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/tokenize/validate       21.00 ± 0%      21.00 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/long_prefix/parse       219.0 ± 0%      219.0 ± 0%       ~ (p=1.000 n=20) ¹
ParseError/long_prefix/validate    219.0 ± 0%      219.0 ± 0%       ~ (p=1.000 n=20) ¹
geomean                                       ²                +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                          │    base     │                head                │
                          │  sec/stmt   │  sec/stmt    vs base               │
ParseRW/postgresql/medium   13.91µ ± 1%   13.96µ ± 1%       ~ (p=0.387 n=20)
ParseRW/mysql/medium        12.01µ ± 1%   12.05µ ± 1%       ~ (p=0.380 n=20)
ParseRW/mariadb/medium      15.22µ ± 1%   15.25µ ± 0%       ~ (p=0.449 n=20)
ParseRW/sqlserver/medium    13.00µ ± 1%   12.97µ ± 1%       ~ (p=0.533 n=20)
ParseRW/oracle/medium       13.52µ ± 1%   13.53µ ± 1%       ~ (p=0.597 n=20)
ParseRW/sqlite/medium       12.04µ ± 2%   12.08µ ± 3%       ~ (p=0.380 n=20)
ParseRW/snowflake/medium    14.52µ ± 1%   14.60µ ± 1%       ~ (p=0.457 n=20)
ParseRW/clickhouse/medium   13.15µ ± 3%   12.71µ ± 3%       ~ (p=0.142 n=20)
geomean                     13.38µ        13.35µ       -0.23%

pkg: github.com/ajitpratap0/GoSQLX/pkg/linter
                   │     base     │                head                 │
                   │    sec/op    │    sec/op     vs base               │
LintParallel/rules   35.59m ±  1%   35.84m ±  1%       ~ (p=0.265 n=20)
LintParallel/lint    54.99m ±  2%   55.61m ±  1%       ~ (p=0.659 n=20)
LintRW/postgresql    7.173m ±  3%   7.175m ±  1%       ~ (p=0.478 n=20)
LintRW/mysql         7.442m ±  1%   7.471m ±  1%       ~ (p=0.602 n=20)
LintRW/mariadb       6.821m ±  2%   6.907m ±  1%       ~ (p=0.301 n=20)
LintRW/sqlserver     6.423m ±  1%   6.488m ±  1%       ~ (p=0.063 n=20)
LintRW/oracle        7.694m ±  2%   7.762m ±  1%       ~ (p=0.883 n=20)
LintRW/sqlite        6.509m ±  2%   6.523m ±  4%       ~ (p=0.565 n=20)
LintRW/snowflake     6.633m ±  4%   6.605m ±  3%       ~ (p=0.659 n=20)
LintRW/clickhouse    7.347m ±  4%   7.528m ±  5%       ~ (p=0.565 n=20)
LintRule/L007        7.907m ±  2%   7.950m ±  1%       ~ (p=0.738 n=20)
LintRule/L010        702.9µ ± 26%   890.7µ ± 21%       ~ (p=0.018 n=20)
geomean              7.933m         8.146m        +2.69%

                  │     base     │                head                 │
                  │     B/s      │     B/s       vs base               │
LintRW/postgresql   3.948Mi ± 3%   3.943Mi ± 1%       ~ (p=0.456 n=20)
LintRW/mysql        4.396Mi ± 1%   4.377Mi ± 1%       ~ (p=0.606 n=20)
LintRW/mariadb      4.473Mi ± 1%   4.416Mi ± 1%       ~ (p=0.291 n=20)
LintRW/sqlserver    4.821Mi ± 1%   4.778Mi ± 1%       ~ (p=0.058 n=20)
LintRW/oracle       5.159Mi ± 2%   5.121Mi ± 1%       ~ (p=0.878 n=20)
LintRW/sqlite       4.411Mi ± 2%   4.396Mi ± 4%       ~ (p=0.615 n=20)
LintRW/snowflake    4.702Mi ± 4%   4.725Mi ± 3%       ~ (p=0.644 n=20)
LintRW/clickhouse   4.420Mi ± 4%   4.311Mi ± 5%       ~ (p=0.653 n=20)
geomean             4.529Mi        4.496Mi       -0.72%

                   │      base      │                 head                  │
                   │      B/op      │     B/op      vs base                 │
LintParallel/rules   10.96Mi ± 0%     10.96Mi ± 0%       ~ (p=0.909 n=20)
LintParallel/lint    30.93Mi ± 0%     30.93Mi ± 0%       ~ (p=0.499 n=20)
LintRW/postgresql    3.402Mi ± 0%     3.402Mi ± 0%       ~ (p=0.274 n=20)
LintRW/mysql         4.243Mi ± 0%     4.243Mi ± 0%       ~ (p=0.984 n=20)
LintRW/mariadb       3.924Mi ± 0%     3.924Mi ± 0%       ~ (p=0.713 n=20)
LintRW/sqlserver     3.488Mi ± 0%     3.488Mi ± 0%       ~ (p=0.753 n=20)
LintRW/oracle        4.242Mi ± 0%     4.242Mi ± 0%       ~ (p=0.588 n=20)
LintRW/sqlite        3.697Mi ± 0%     3.697Mi ± 0%       ~ (p=0.836 n=20)
LintRW/snowflake     3.745Mi ± 0%     3.745Mi ± 0%       ~ (p=0.899 n=20)
LintRW/clickhouse    4.190Mi ± 0%     4.190Mi ± 0%       ~ (p=0.059 n=20)
LintRule/L007        2.942Mi ± 0%     2.942Mi ± 0%       ~ (p=0.176 n=20)
LintRule/L010          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                           ²                 +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                   │     base      │                 head                 │
                   │   allocs/op   │  allocs/op   vs base                 │
LintParallel/rules   229.7k ± 0%     229.7k ± 0%       ~ (p=0.727 n=20)
LintParallel/lint    308.3k ± 0%     308.3k ± 0%       ~ (p=0.802 n=20)
LintRW/postgresql    34.19k ± 0%     34.19k ± 0%       ~ (p=0.205 n=20)
LintRW/mysql         41.49k ± 0%     41.49k ± 0%       ~ (p=1.000 n=20)
LintRW/mariadb       38.23k ± 0%     38.23k ± 0%       ~ (p=0.661 n=20)
LintRW/sqlserver     34.62k ± 0%     34.62k ± 0%       ~ (p=1.000 n=20) ¹
LintRW/oracle        42.24k ± 0%     42.24k ± 0%       ~ (p=1.000 n=20)
LintRW/sqlite        37.58k ± 0%     37.58k ± 0%       ~ (p=1.000 n=20) ¹
LintRW/snowflake     37.56k ± 0%     37.56k ± 0%       ~ (p=1.000 n=20)
LintRW/clickhouse    42.34k ± 0%     42.34k ± 0%       ~ (p=1.000 n=20) ¹
LintRule/L007        72.56k ± 0%     72.56k ± 0%       ~ (p=1.000 n=20) ¹
LintRule/L010         0.000 ± 0%      0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                          ²                -0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                  │     base     │                head                 │
                  │   sec/stmt   │   sec/stmt    vs base               │
LintRW/postgresql   23.52µ ±  3%   23.53µ ±  1%       ~ (p=0.478 n=20)
LintRW/mysql        17.98µ ±  1%   18.05µ ±  1%       ~ (p=0.588 n=20)
LintRW/mariadb      17.95µ ±  2%   18.18µ ±  1%       ~ (p=0.301 n=20)
LintRW/sqlserver    23.19µ ±  1%   23.42µ ±  1%       ~ (p=0.064 n=20)
LintRW/oracle       20.91µ ±  2%   21.09µ ±  1%       ~ (p=0.883 n=20)
LintRW/sqlite       18.70µ ±  2%   18.74µ ±  4%       ~ (p=0.560 n=20)
LintRW/snowflake    20.28µ ±  4%   20.20µ ±  3%       ~ (p=0.654 n=20)
LintRW/clickhouse   18.65µ ±  4%   19.11µ ±  5%       ~ (p=0.551 n=20)
LintRule/L007       2.811µ ±  2%   2.826µ ±  1%       ~ (p=0.723 n=20)
LintRule/L010       249.9n ± 26%   316.7n ± 21%       ~ (p=0.018 n=20)
geomean             10.62µ         10.95µ        +3.05%

pkg: github.com/ajitpratap0/GoSQLX/pkg/sql/tokenizer
                         │    base     │                head                │
                         │   sec/op    │   sec/op     vs base               │
Tokenize/scratch/join      1.454µ ± 2%   1.471µ ± 2%       ~ (p=0.973 n=20)
Tokenize/scratch/complex   3.833µ ± 1%   3.830µ ± 1%       ~ (p=0.888 n=20)
Tokenize/scratch/insert    722.4n ± 4%   741.8n ± 2%       ~ (p=0.640 n=20)
geomean                    1.591µ        1.611µ       +1.25%

                         │     base      │                head                 │
                         │      B/s      │     B/s       vs base               │
Tokenize/scratch/join       82.67Mi ± 2%   81.71Mi ± 2%       ~ (p=0.968 n=20)
Tokenize/scratch/complex    94.04Mi ± 1%   94.12Mi ± 1%       ~ (p=0.899 n=20)
Tokenize/scratch/insert    100.33Mi ± 3%   97.71Mi ± 2%       ~ (p=0.640 n=20)
geomean                     92.05Mi        90.92Mi       -1.23%

                         │     base     │                head                 │
                         │     B/op     │    B/op     vs base                 │
Tokenize/scratch/join      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/complex   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/insert    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                               ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                         │     base     │                head                 │
                         │  allocs/op   │ allocs/op   vs base                 │
Tokenize/scratch/join      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/complex   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
Tokenize/scratch/insert    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                               ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/ajitpratap0/GoSQLX/pkg/transform
                             │    base     │                head                │
                             │   sec/op    │   sec/op     vs base               │
TransformParse/simple_select   1.516µ ± 1%   1.519µ ± 2%       ~ (p=0.317 n=20)
TransformParse/join            4.969µ ± 1%   4.941µ ± 1%       ~ (p=0.218 n=20)
TransformParse/complex         13.01µ ± 1%   13.13µ ± 2%       ~ (p=0.429 n=20)
geomean                        4.610µ        4.618µ       +0.18%

                             │     base     │                 head                  │
                             │     B/op     │     B/op      vs base                 │
TransformParse/simple_select     816.0 ± 0%     816.0 ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/join            1.836Ki ± 0%   1.836Ki ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/complex         5.023Ki ± 0%   5.023Ki ± 0%       ~ (p=1.000 n=20) ¹
geomean                        1.944Ki        1.944Ki       +0.00%
¹ all samples are equal

                             │    base    │                head                 │
                             │ allocs/op  │ allocs/op   vs base                 │
TransformParse/simple_select   5.000 ± 0%   5.000 ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/join            17.00 ± 0%   17.00 ± 0%       ~ (p=1.000 n=20) ¹
TransformParse/complex         49.00 ± 0%   49.00 ± 0%       ~ (p=1.000 n=20) ¹
geomean                        16.09        16.09       +0.00%
¹ all samples are equal

Run, raw data and benchstat

This branch was successfully deployed

1 active deployment
Preview — c7ddd49c Deployed Nov 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dialects documentation Improvements or additions to documentation performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant