Skip to content

BE-641: Extend the SQL AST along gram.y and make invalid SQL unrepresentable#9033

Open
TimDiekmann wants to merge 20 commits into
mainfrom
t/be-641-extend-the-sql-ast
Open

BE-641: Extend the SQL AST along gram.y and make invalid SQL unrepresentable#9033
TimDiekmann wants to merge 20 commits into
mainfrom
t/be-641-extend-the-sql-ast

Conversation

@TimDiekmann

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

Extends the SQL statement AST in hash-graph-postgres-store so that every Postgres statement we need is expressible in typed Rust, modelled strictly along Postgres' grammar (gram.y): at most the grammar per node — invalid SQL is unrepresentable — with completeness added on demand. On top of the structural work, the SelectCompiler no longer uses the AST as mutable working state: it keeps its own bookkeeping and assembles the statement in compile(), which is the groundwork for the BE-598 query-shape changes.

Stacked on #9020 (module restructure); only the commits of this branch are new.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

Grammar-faithful AST (per node: at most gram.y):

  • WITH: CTEs with plain [TableName]s, MATERIALIZED/NOT MATERIALIZED hints, optional column lists, and WITH RECURSIVE; the clause holds a NonEmptyVec<CommonTableExpression>
  • The SELECT three-way split along gram.y: SimpleSelect (simple_select), SelectClause (set-operation tree: UNION/INTERSECT/EXCEPT [ALL], operands parenthesized so Postgres re-parses the exact tree), SelectStatement (select_no_parens: WITH/ORDER BY/LIMIT/OFFSET) — clause placement rules are now type-structural (no ORDER BY on a bare set-operation operand)
  • GROUP BY [ALL|DISTINCT] grouping_element [, …] with GroupingElement::{Empty, Expressions} (ROLLUP/CUBE/GROUPING SETS fenced off), HAVING, hardened WindowDefinition (PARTITION BY only, non-empty), TABLESAMPLE with finite SamplePercentage
  • WHERE is Option<Expression> (the grammar's [ WHERE condition ]); ORDER BY uses AST-own SortBy/SortDirection/NullsOrder (gram.y sortby), decoupling the AST from store types
  • NonEmptyVec<T> as the list-invariant helper (grow-only, no shrink API, Deref<[T]>); target lists, CTE lists, DISTINCT ON, PARTITION BY, and sort lists are non-empty by construction
  • Fixed a latent clause-order bug: ORDER BY was emitted before GROUP BY (never hit because no statement set both)

Builder composition:

  • bon builders throughout with #[builder(derive(Into))] conversion chains: builders flow into impl Into slots, .build() only remains at the outermost edge; NonEmptyVec members use plain #[builder(into)] setters (single element and ready-made vec convert infallibly, a raw Vec parses visibly via NonEmptyVec::try_from)

Compiler decomposition:

  • SelectCompiler keeps selects/from/quantifier/with/conditions/cursor/sort_by/limit as its own fields and assembles the statement in compile(); join bookkeeping lives in mirrored CompiledJoin records instead of reading the statement tree back, and Table::aliased_name is the single owner of alias-name mangling
  • The keyset cursor is built as an Expression tree; nulls: None now mirrors Postgres' actual default (ASC → NULLS LAST, DESC → NULLS FIRST) — previously unhinted ascending sorts over nullable keys silently lost their NULL rows during pagination. Provably NOT NULL sort keys (verified whitelist Column::NON_NULL_COLUMNS) skip the null-handling arms, keeping the hot default-sort predicates bare
  • Silent failure modes made loud: empty Identifiers panic at construction, parameters with pending conversions return PendingParameterConversion instead of unimplemented!, and a second embeddings distance filter is rejected via an explicit flag (previously it silently reinstalled the subquery with mismatched parameters)

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • The emitted SQL changed shape: top-level WHERE conjuncts are now individually parenthesized and the cursor continuation is an expression tree. Semantically identical (validated by executing the hashql E2E suite and the integration tests against real Postgres), but pg_stat_statements will mint new query IDs — dashboards comparing against old fingerprints reset.
  • The cursor port fixes two latent invalid-SQL edge cases of the old string-based WHERE builder (empty conditions combined with a cursor produced WHERE AND (…) / a dangling WHERE).
  • Documented grammar subsets remain (fenced in the doc comments): LIMIT/OFFSET as expressions (LIMIT $1), FETCH, locking clauses, VALUES/TABLE/parenthesized set-operation operands, the statement-level WINDOW clause, ROLLUP/CUBE/GROUPING SETS, ORDER BY … USING op, SEARCH/CYCLE.
  • FromItem still allows a USING join with an empty column list (degrades to ON TRUE, documented); the structural fix is bundled with the BE-528 column_definitions work, which touches the same grammar production.

🐾 Next steps

  • Subquery predicates (EXISTS, IN (SELECT …)) as the last planned AST block
  • BE-528 bundle: column_definitions for typed JSON + AliasClause pairing / USING non-emptiness
  • BE-699: complete Column::nullable() or generate the schema mirror from migrations
  • BE-598: the fetch-keys-then-hydrate query shape on top of the decomposed compiler

🛡 What tests cover this?

  • 164 unit tests in hash-graph-postgres-store (golden SQL for every compiler shape, all cursor_condition branches — previously untested —, per-clause transpile tests, NonEmptyVec invariants)
  • tests/schema.rs: verifies Column::NON_NULL_COLUMNS against information_schema of the live database
  • 98 hashql E2E tests (execute the emitted SQL against Postgres via testcontainers; 4 snapshots regenerated, diffs are pure added parentheses)
  • 24 sorting/pagination integration tests (nullable keys, NULLS FIRST/LAST mixes, cursor loops against real data)

❓ How to test this?

  1. cargo nextest run --package hash-graph-postgres-store --lib
  2. cargo nextest run --package hashql-eval (needs Docker for testcontainers)
  3. With a migrated local database: cargo nextest run --package hash-graph-postgres-store --test schema and cargo nextest run -p hash-graph-integration --test postgres -E 'test(sorting)'

📹 Demo

WithClause::builder()
    .recursive(true)
    .common_table_expressions(
        CommonTableExpression::builder().name("traversal").statement(
            SelectClause::from(base_case).union_all(recursive_case),
        ),
    )
    .build()
WITH RECURSIVE "traversal" AS (SELECT * FROM "data_types"
UNION ALL
SELECT * FROM "property_types")

@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jul 16, 2026 9:14am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jul 16, 2026 9:14am
petrinaut Skipped Skipped Jul 16, 2026 9:14am

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team area/tests New or updated tests labels Jul 15, 2026
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.58716% with 59 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.31%. Comparing base (0cb749d) to head (6753875).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...gres-store/src/store/postgres/query/compile/mod.rs 90.94% 19 Missing and 3 partials ⚠️
...es-store/src/store/postgres/query/ast/non_empty.rs 80.32% 12 Missing ⚠️
...tore/postgres/query/ast/statement/select/simple.rs 88.88% 8 Missing ⚠️
...tore/postgres/query/ast/statement/select/clause.rs 94.39% 6 Missing ⚠️
...c/store/postgres/query/ast/statement/select/mod.rs 95.45% 3 Missing ⚠️
.../postgres/query/ast/statement/select/quantifier.rs 91.17% 3 Missing ⚠️
...re/src/store/postgres/query/ast/table_reference.rs 25.00% 3 Missing ⚠️
...s-store/src/store/postgres/query/ast/identifier.rs 90.00% 1 Missing ⚠️
libs/@local/hashql/eval/src/postgres/mod.rs 93.75% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9033      +/-   ##
==========================================
+ Coverage   59.19%   59.31%   +0.11%     
==========================================
  Files        1389     1393       +4     
  Lines      135001   135212     +211     
  Branches     6183     6183              
==========================================
+ Hits        79910    80196     +286     
+ Misses      54151    54086      -65     
+ Partials      940      930      -10     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.92% <ø> (ø)
apps.hash-api 7.59% <ø> (ø)
local.hash-backend-utils 1.88% <ø> (ø)
local.hash-graph-sdk 10.02% <ø> (ø)
local.hash-isomorphic-utils 0.17% <ø> (ø)
rust.hash-graph-api 7.41% <ø> (ø)
rust.hash-graph-postgres-store 26.04% <94.49%> (+1.44%) ⬆️
rust.hashql-compiletest 28.39% <ø> (ø)
rust.hashql-eval 79.82% <97.22%> (-0.23%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing t/be-641-extend-the-sql-ast (a2a0e6d) with main (03f6a30)1

Open in CodSpeed

Footnotes

  1. No successful run was found on t/be-641-statement-layer-make-every-postgres-statement-we-need (4a6acd2) during the generation of this report, so main (03f6a30) was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Base automatically changed from t/be-641-statement-layer-make-every-postgres-statement-we-need to main July 15, 2026 15:46
@TimDiekmann
TimDiekmann force-pushed the t/be-641-extend-the-sql-ast branch from a2a0e6d to 0a85270 Compare July 15, 2026 17:27
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 15, 2026 17:27 Inactive
@github-actions github-actions Bot removed the area/deps Relates to third-party dependencies (area) label Jul 15, 2026
@TimDiekmann
TimDiekmann marked this pull request as ready for review July 15, 2026 18:41
Copilot AI review requested due to automatic review settings July 15, 2026 18:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches all compiled SELECT SQL (pagination, embeddings distance, CTE latest-version), with emitted SQL shape changes that affect query fingerprints even when semantics stay the same.

Overview
Restructures the Postgres query AST to follow gram.y: SimpleSelect, SelectClause (set ops with parenthesized operands), and SelectStatement (WITH / ORDER BY / LIMIT / OFFSET); replaces ad-hoc clause types with WithClause, GroupByClause, OrderByClause, and a plain Option<Expression> for WHERE. NonEmptyVec, SelectQuantifier, and finite SamplePercentage block empty or invalid SQL at construction; FromItem / TableReference now use plain TableName aliases via Table::aliased_name instead of nested TableReference + Alias.

SelectCompiler no longer mutates a full statement tree: it keeps selects, joins, filters, cursor keys, and sort keys locally, tracks joins in CompiledJoin, and assembles the AST in compile(). Keyset pagination moves from the deleted string-based WhereExpression to an Expression continuation that matches Postgres default NULLS ordering and can skip null arms for provably non-null keys; Expression::conjunction / disjunction fold single conditions without extra wrapping. Failures are explicit: empty identifiers panic, pending parameter conversions return PendingParameterConversion, and a second embeddings distance filter is rejected instead of silently rewriting the top join.

Reviewed by Cursor Bugbot for commit 6753875. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 644b7be. Configure here.

Copilot AI review requested due to automatic review settings July 16, 2026 08:58
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 08:58 Inactive

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$26.2 \mathrm{ms} \pm 206 \mathrm{μs}\left({\color{gray}-1.950 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.46 \mathrm{ms} \pm 22.5 \mathrm{μs}\left({\color{gray}0.003 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$12.8 \mathrm{ms} \pm 86.1 \mathrm{μs}\left({\color{gray}-0.553 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$43.9 \mathrm{ms} \pm 353 \mathrm{μs}\left({\color{gray}0.996 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$15.0 \mathrm{ms} \pm 156 \mathrm{μs}\left({\color{gray}0.504 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$24.4 \mathrm{ms} \pm 146 \mathrm{μs}\left({\color{gray}-0.227 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$27.1 \mathrm{ms} \pm 197 \mathrm{μs}\left({\color{gray}-0.821 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.75 \mathrm{ms} \pm 20.6 \mathrm{μs}\left({\color{gray}-0.730 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.6 \mathrm{ms} \pm 89.6 \mathrm{μs}\left({\color{gray}-1.438 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.76 \mathrm{ms} \pm 23.3 \mathrm{μs}\left({\color{gray}-0.564 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.03 \mathrm{ms} \pm 19.3 \mathrm{μs}\left({\color{gray}-1.091 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$3.37 \mathrm{ms} \pm 18.9 \mathrm{μs}\left({\color{gray}-0.146 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.13 \mathrm{ms} \pm 37.0 \mathrm{μs}\left({\color{gray}-1.917 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.58 \mathrm{ms} \pm 21.4 \mathrm{μs}\left({\color{gray}-0.133 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$4.09 \mathrm{ms} \pm 22.9 \mathrm{μs}\left({\color{gray}-0.354 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.31 \mathrm{ms} \pm 25.6 \mathrm{μs}\left({\color{gray}-1.981 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.46 \mathrm{ms} \pm 22.1 \mathrm{μs}\left({\color{gray}-1.287 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.02 \mathrm{ms} \pm 25.7 \mathrm{μs}\left({\color{gray}-1.204 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.58 \mathrm{ms} \pm 12.4 \mathrm{μs}\left({\color{gray}-4.856 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.54 \mathrm{ms} \pm 18.4 \mathrm{μs}\left({\color{gray}-0.607 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.60 \mathrm{ms} \pm 15.4 \mathrm{μs}\left({\color{gray}-3.840 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.84 \mathrm{ms} \pm 13.5 \mathrm{μs}\left({\color{lightgreen}-6.558 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.68 \mathrm{ms} \pm 15.3 \mathrm{μs}\left({\color{gray}-3.502 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.84 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}-4.343 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.03 \mathrm{ms} \pm 13.6 \mathrm{μs}\left({\color{gray}-0.142 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.79 \mathrm{ms} \pm 13.5 \mathrm{μs}\left({\color{gray}0.039 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$3.00 \mathrm{ms} \pm 24.0 \mathrm{μs}\left({\color{gray}0.761 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.40 \mathrm{ms} \pm 21.3 \mathrm{μs}\left({\color{gray}-1.553 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.04 \mathrm{ms} \pm 25.5 \mathrm{μs}\left({\color{gray}1.13 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$3.32 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{gray}2.38 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.33 \mathrm{ms} \pm 14.5 \mathrm{μs}\left({\color{gray}-1.005 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.01 \mathrm{ms} \pm 16.0 \mathrm{μs}\left({\color{gray}0.505 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.30 \mathrm{ms} \pm 17.0 \mathrm{μs}\left({\color{gray}0.996 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$41.9 \mathrm{ms} \pm 185 \mathrm{μs}\left({\color{gray}-1.308 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$33.4 \mathrm{ms} \pm 138 \mathrm{μs}\left({\color{gray}-1.131 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$36.1 \mathrm{ms} \pm 249 \mathrm{μs}\left({\color{gray}0.407 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$37.5 \mathrm{ms} \pm 1.08 \mathrm{ms}\left({\color{red}14.6 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$42.9 \mathrm{ms} \pm 242 \mathrm{μs}\left({\color{gray}-2.794 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$49.6 \mathrm{ms} \pm 261 \mathrm{μs}\left({\color{gray}1.16 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$41.2 \mathrm{ms} \pm 239 \mathrm{μs}\left({\color{gray}-0.839 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$93.8 \mathrm{ms} \pm 845 \mathrm{μs}\left({\color{gray}1.26 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$34.5 \mathrm{ms} \pm 179 \mathrm{μs}\left({\color{gray}-0.581 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$256 \mathrm{ms} \pm 861 \mathrm{μs}\left({\color{lightgreen}-16.422 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$11.1 \mathrm{ms} \pm 48.8 \mathrm{μs}\left({\color{gray}-1.573 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$11.3 \mathrm{ms} \pm 59.6 \mathrm{μs}\left({\color{gray}1.63 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$11.2 \mathrm{ms} \pm 73.8 \mathrm{μs}\left({\color{gray}1.50 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$11.1 \mathrm{ms} \pm 63.4 \mathrm{μs}\left({\color{gray}-0.136 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$11.3 \mathrm{ms} \pm 60.8 \mathrm{μs}\left({\color{gray}1.51 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$11.1 \mathrm{ms} \pm 59.4 \mathrm{μs}\left({\color{gray}0.829 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$11.5 \mathrm{ms} \pm 75.7 \mathrm{μs}\left({\color{gray}2.45 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$11.2 \mathrm{ms} \pm 62.0 \mathrm{μs}\left({\color{gray}0.055 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$11.5 \mathrm{ms} \pm 85.7 \mathrm{μs}\left({\color{gray}2.82 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$12.0 \mathrm{ms} \pm 187 \mathrm{μs}\left({\color{red}6.15 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$11.6 \mathrm{ms} \pm 72.9 \mathrm{μs}\left({\color{gray}-2.599 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$11.8 \mathrm{ms} \pm 63.2 \mathrm{μs}\left({\color{gray}0.927 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$11.6 \mathrm{ms} \pm 60.0 \mathrm{μs}\left({\color{gray}-0.919 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$11.6 \mathrm{ms} \pm 61.0 \mathrm{μs}\left({\color{gray}-3.010 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$11.6 \mathrm{ms} \pm 107 \mathrm{μs}\left({\color{gray}-0.911 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$11.9 \mathrm{ms} \pm 71.1 \mathrm{μs}\left({\color{gray}0.893 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$11.6 \mathrm{ms} \pm 64.7 \mathrm{μs}\left({\color{gray}-0.828 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$11.7 \mathrm{ms} \pm 66.8 \mathrm{μs}\left({\color{gray}0.184 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$11.6 \mathrm{ms} \pm 74.3 \mathrm{μs}\left({\color{gray}-1.154 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$8.49 \mathrm{ms} \pm 38.6 \mathrm{μs}\left({\color{gray}-2.326 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$60.4 \mathrm{ms} \pm 327 \mathrm{μs}\left({\color{gray}-1.979 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$112 \mathrm{ms} \pm 514 \mathrm{μs}\left({\color{gray}-1.924 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$68.4 \mathrm{ms} \pm 526 \mathrm{μs}\left({\color{gray}-2.773 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$77.4 \mathrm{ms} \pm 507 \mathrm{μs}\left({\color{gray}-0.123 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$87.3 \mathrm{ms} \pm 772 \mathrm{μs}\left({\color{gray}1.30 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$91.6 \mathrm{ms} \pm 538 \mathrm{μs}\left({\color{gray}-0.090 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$45.2 \mathrm{ms} \pm 312 \mathrm{μs}\left({\color{gray}-2.439 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$72.6 \mathrm{ms} \pm 347 \mathrm{μs}\left({\color{gray}-0.895 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$50.6 \mathrm{ms} \pm 280 \mathrm{μs}\left({\color{gray}-2.732 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$59.9 \mathrm{ms} \pm 355 \mathrm{μs}\left({\color{gray}-1.182 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$62.2 \mathrm{ms} \pm 361 \mathrm{μs}\left({\color{gray}-0.627 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$62.0 \mathrm{ms} \pm 351 \mathrm{μs}\left({\color{gray}-1.664 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$123 \mathrm{ms} \pm 652 \mathrm{μs}\left({\color{gray}-4.969 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$134 \mathrm{ms} \pm 403 \mathrm{μs}\left({\color{lightgreen}-5.181 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$23.8 \mathrm{ms} \pm 172 \mathrm{μs}\left({\color{red}31.8 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$583 \mathrm{ms} \pm 994 \mathrm{μs}\left({\color{red}6.77 \mathrm{\%}}\right) $$ Flame Graph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

2 participants