Benchmark: databend-common-ast vs other Rust SQL parsers on PostgreSQL workloads #19485
LucaCappelletti94
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
I have published an open-source benchmark comparing Rust SQL parsers on real-world PostgreSQL statements, including
databend-common-ast. Sharing the results here as they may be useful to the team.Benchmark repo: https://github.com/LucaCappelletti94/sql_ast_benchmark
What the benchmark measures
Performance: parse throughput on the Spider + Gretel PostgreSQL datasets (4,505 statements: SELECT, INSERT, UPDATE, DELETE), measured at batch sizes 1–1000.
Correctness: evaluated against the sqlparser-rs test suite using
pg_query.rs(libpg_query - the actual PostgreSQL parser) as ground truth. Four metrics:parse → print → re-parse → re-printproduces identical output?pg_query_canonical(parser_output) == pg_query_canonical(original)- semantically correct output, not just self-consistent?Performance results
Methodology note
databend-common-astparses one statement per call, so the benchmark splits the concatenated input on;and invokes the parser once per statement. This matches the natural API contract but adds a small string-splitting overhead compared to parsers that accept a multi-statement string natively.SELECT throughput (batch of N statements)
Other statement types (full corpus batch)
databend-common-ast is consistently within 10–30% of sqlparser-rs wall-clock time. For INSERT/UPDATE/DELETE the gap narrows to under 10%.
Parse success rate on real-world corpus (Spider + Gretel, PostgreSQL-validated)
The 1–6% failures reflect PostgreSQL-specific constructs (
RETURNING, certain type casts, PG-specific syntax) that fall outside the Databend/ClickHouse dialect focus.Correctness results
Tested against the sqlparser-rs test suite on three corpora, using pg_query as PostgreSQL ground truth. Counts show absolute numbers; percentages are bolded.
PostgreSQL-specific tests (312 valid / 129 invalid)
Common (all-dialect) tests (323 valid / 469 invalid)
TPC-H / regression tests (21 valid / 1 invalid)
* This corpus contains only 1 invalid statement; sqlparser-rs accepts it (false positive), databend does not.
Key correctness observations
Strengths:
Lowest false-positive rate of any parser tested: 1.6–7.7% vs sqlparser-rs's 28.7–30.1%. databend-common-ast is the most conservative parser benchmarked - when it accepts SQL, it is almost always genuinely valid PostgreSQL. This is a strong property for applications that need strict dialect enforcement.
Perfect round-trip stability: every statement that databend-common-ast accepts round-trips cleanly through
parse → print → re-parse → re-print. Zero regressions observed across all corpora.Strong TPC-H / analytical SQL recall (95%): for complex analytical queries (multi-join, aggregations, subqueries, window functions), databend-common-ast handles nearly everything sqlparser-rs does. This suggests the core SQL expression and query grammar is solid.
Areas for improvement:
Low recall on PostgreSQL-specific syntax (13%): the PG-specific corpus covers DDL extensions and PostgreSQL type system features (
ENUM,DOMAIN,SEQUENCE, PG-specific operators, array syntax, etc.). Most failures are expected given the Databend/ClickHouse dialect focus, but these are the concrete gaps if PostgreSQL compatibility is a goal.Moderate recall on common SQL (55%): even on standard SQL constructs shared across dialects, databend-common-ast accepts 55% of what pg_query accepts (vs 98% for sqlparser-rs). This suggests several common SQL constructs are not yet supported beyond the Databend dialect.
Fidelity gap on accepted statements: among statements the parser accepts, 77.5–84.7% produce semantically equivalent output under pg_query's canonical form (vs 98.7–100% for sqlparser-rs). Round-trip is perfect (the parser is self-consistent), but the pretty-printer normalizes some constructs in ways that change semantics - for example stripping parenthesized join grouping (which also causes the panics above) or altering implicit cast representation.
Reliability concern - panics from internal
assert_reparse:Three statements in the test corpus cause
databend-common-astto panic. The panics do not come from malformed input crashing the parser - the parser succeeds on all three. They originate fromassert_reparseinparser.rs(lines 178/182), a round-trip consistency check called unconditionally after every successful parse. It re-parses the pretty-printed AST and asserts the two ASTs are equal. When the pretty-printer produces inequivalent output, the assertion fires.The three reproduction cases and their root causes:
Two distinct pretty-printer bugs are involved: a spurious comma in
CONSTRAINT ... CHECKoutput, and loss of parenthesized join grouping. Theassert_reparsecheck is called unconditionally (not behind#[cfg(debug_assertions)]), so these panics occur in release builds. The benchmark wraps all databend calls instd::panic::catch_unwindto handle this; without that guard, a panic would abort the calling thread.Summary
databend-common-ast has genuinely impressive properties: the lowest false-positive rate of any pure-Rust parser tested, perfect round-trip stability, strong TPC-H coverage, and wall-clock performance within 10–30% of sqlparser-rs. The primary gap for general-purpose use is recall - particularly on PG-specific and common SQL - which reflects the Databend dialect focus rather than a fundamental design limitation.
If the team is interested in expanding PostgreSQL dialect coverage, the test corpora from this benchmark could be useful as a regression suite. I am happy to open a PR with the raw SQL test files, or to discuss specific failure patterns further.
Thanks for building and maintaining databend-common-ast - it is a well-engineered codebase.
Beta Was this translation helpful? Give feedback.
All reactions