Skip to content

BE-619: Split entity queries and entity counting#8897

Merged
TimDiekmann merged 7 commits into
mainfrom
t/be-619-split-entity-queries-and-entity-counting
Jun 25, 2026
Merged

BE-619: Split entity queries and entity counting#8897
TimDiekmann merged 7 commits into
mainfrom
t/be-619-split-entity-queries-and-entity-counting

Conversation

@TimDiekmann

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

queryEntities / queryEntitySubgraph previously computed the total count and the per-web / per-type facet aggregations inline, coupling the result-set fetch to aggregation work. This splits those aggregations into a dedicated summarizeEntities endpoint, so the page, the count, and the type facets load independently.

🔗 Related links

🔍 What does this change?

  • Adds a summarizeEntities endpoint (POST /entities/query/summarize) returning count plus the webIds / typeIds / typeTitles / created-by aggregations, each gated by an include* flag.
  • Removes the include_count / include_* aggregation flags (and the countEntities endpoint) from queryEntities / queryEntitySubgraph.
  • Migrates the frontend consumers (entities visualizer, type-filter dropdown, account sidebar, draft/notification counts) to the new endpoint; the visualizer now fetches the subgraph, the count, and the type facets as separate queries.
  • Aligns the VersionedUrl / BaseUrl ToSchema output with shared.json (title/description/max_length) to remove duplicate-definition codegen warnings.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies a Cargo-publishable library, but it is not yet ready to publish

📜 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

@vercel

vercel Bot commented Jun 23, 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 Jun 24, 2026 1:49pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jun 24, 2026 1:49pm
petrinaut Skipped Skipped Jun 24, 2026 1:49pm

@github-actions github-actions Bot added area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-api Affects the HASH API (app) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team type/eng > backend Owned by the @backend team area/tests New or updated tests area/apps labels Jun 23, 2026
@vercel vercel Bot temporarily deployed to Preview – petrinaut June 23, 2026 18:51 Inactive
@codspeed-hq

codspeed-hq Bot commented Jun 23, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 24 untouched benchmarks
⏩ 56 skipped benchmarks1


Comparing t/be-619-split-entity-queries-and-entity-counting (94b2f7c) with main (3dbbe7b)2

Open in CodSpeed

Footnotes

  1. 56 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (fd129ea) during the generation of this report, so 3dbbe7b was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@TimDiekmann TimDiekmann marked this pull request as ready for review June 23, 2026 18:56
Copilot AI review requested due to automatic review settings June 23, 2026 18:56
@cursor

cursor Bot commented Jun 23, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches authorization gates (entity permission count), public GraphQL/OpenAPI contracts, and aggregation SQL semantics (edition-based dedup); broad but coordinated migration with test updates.

Overview
Replaces countEntities with summarizeEntities (POST /entities/query/summarize), returning optional count, per-typeIds/typeTitles, webIds, and created-by breakdowns behind include* flags. queryEntities and queryEntitySubgraph no longer run inline aggregations—those include_* flags and summary fields are removed from their params and responses.

GraphQL exposes summarizeEntities instead of countEntities. Frontend (entities visualizer, sidebar type counts, drafts/notifications/waitlist) calls the new query, often in parallel with subgraph/list fetches. Postgres moves summary SQL into summarize_entities only; EntitySummaryQuery dedupes by edition_id, folds type titles into the type aggregate branch, and drops the separate type-title lookup query.

Permission check in hash-api uses summarizeEntities with includeCount: true and treats missing/zero count as deny. Flow runs load rows via queryEntities and total count via concurrent summarizeEntities, with shared semantic filter rewrite. OpenAPI BaseUrl/VersionedUrl schemas gain title, description, and maxLength for codegen alignment.

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

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.

Pull request overview

Decouples entity result fetching from aggregation work by introducing a dedicated entity summary endpoint (summarizeEntities), and migrates API/SDK/GraphQL/frontend consumers away from inline counts/facets on queryEntities / queryEntitySubgraph. Also aligns OpenAPI schema metadata for BaseUrl / VersionedUrl with shared.json to reduce duplicate-definition/codegen warnings.

Changes:

  • Adds summarizeEntities / /entities/query/summarize with opt-in aggregation flags and removes count/facet flags from entity query endpoints.
  • Updates Rust store APIs, GraphQL schema/resolvers, TypeScript SDK helpers, and frontend queries to use the new summary endpoint.
  • Updates integration tests/benches to match the new query + summary split; improves OpenAPI schema metadata consistency.

Reviewed changes

Copilot reviewed 46 out of 46 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/graph/integration/postgres/sorting.rs Updates subgraph query usage after removing inline count/aggregations.
tests/graph/integration/postgres/partial_updates.rs Removes deprecated include-count/aggregation flags from queries.
tests/graph/integration/postgres/multi_type.rs Adds/uses summarize_entities in tests verifying aggregations.
tests/graph/integration/postgres/links.rs Migrates link existence checks from count_entities to summarize_entities.
tests/graph/integration/postgres/lib.rs Adjusts test EntityStore wrapper to delegate summarize_entities.
tests/graph/integration/postgres/entity.rs Migrates count assertions to summarize_entities and removes inline count expectations.
tests/graph/integration/postgres/email_filter_protection.rs Switches filter-protected counting helper to summarize_entities.
tests/graph/benches/representative_read/knowledge/entity.rs Removes deprecated query flags in bench requests.
tests/graph/benches/read_scaling/knowledge/linkless/entity.rs Removes deprecated query flags in bench requests.
tests/graph/benches/read_scaling/knowledge/complete/entity.rs Removes deprecated query flags in bench requests.
tests/graph/benches/manual_queries/entity_queries/mod.rs Removes include_count permutations from manual bench query generation.
tests/graph/benches/graph/scenario/stages/entity_queries.rs Updates scenario bench query params after removing inline aggregations.
libs/@local/hashql/mir/src/interpret/suspension/mod.rs Adjusts debug_assert_matches usage/imports.
libs/@local/hash-isomorphic-utils/src/graphql/type-defs/knowledge/entity.typedef.ts Replaces countEntities GraphQL query with summarizeEntities.
libs/@local/hash-isomorphic-utils/src/graphql/scalar-mapping.ts Updates scalar mappings for summarize request/response types.
libs/@local/hash-backend-utils/src/flows.ts Uses summarizeEntities for total counts while querying pages independently.
libs/@local/graph/type-fetcher/src/store.rs Renames count_entities to summarize_entities in store wrapper.
libs/@local/graph/store/src/entity/store.rs Introduces SummarizeEntitiesParams/Response and removes count/facets from query responses.
libs/@local/graph/store/src/entity/mod.rs Re-exports summarize types instead of count types.
libs/@local/graph/sdk/typescript/src/entity.ts Adds summarizeEntities() helper and removes facet fields from subgraph query mapping.
libs/@local/graph/postgres-store/tests/deletion/validation.rs Renames helper usage to count_entities (plural) backed by summarization.
libs/@local/graph/postgres-store/tests/deletion/purge.rs Migrates deletion tests to new counting helper.
libs/@local/graph/postgres-store/tests/deletion/main.rs Updates shared deletion test helper to call summarize_entities and extract count.
libs/@local/graph/postgres-store/tests/deletion/links.rs Migrates deletion link tests to new counting helper.
libs/@local/graph/postgres-store/tests/deletion/erase.rs Migrates erase tests to new counting helper.
libs/@local/graph/postgres-store/tests/deletion/drafts.rs Migrates draft deletion tests to new counting helper.
libs/@local/graph/postgres-store/src/store/postgres/knowledge/entity/summary.rs Updates summary query builder to use SummarizeEntitiesParams.
libs/@local/graph/postgres-store/src/store/postgres/knowledge/entity/mod.rs Removes inline query aggregations and implements summarize_entities.
libs/@local/graph/api/src/rest/mod.rs Renames OpenAPI query logger variant to SummarizeEntities.
libs/@local/graph/api/src/rest/json_schemas/shared.json Fixes BaseUrl description grammar.
libs/@local/graph/api/src/rest/entity.rs Replaces REST /count with /summarize and returns structured summary response.
libs/@local/graph/api/src/rest/entity_query_request.rs Removes deprecated include-count/aggregation options from query request parsing.
libs/@local/graph/api/openapi/openapi.json Updates OpenAPI paths/schemas to include SummarizeEntities* and metadata alignment.
libs/@local/graph/api/openapi/models/shared.json Fixes BaseUrl description grammar in generated models.
libs/@blockprotocol/type-system/rust/src/ontology/id/mod.rs Adds title/description/maxLength metadata for URL schema types.
apps/hash-frontend/src/shared/notification-count-context.tsx Switches unread notification counting to summarizeEntities.
apps/hash-frontend/src/shared/layout/layout-with-sidebar/sidebar/account-entities-list.tsx Uses summary typeId counts to filter sidebar entity types.
apps/hash-frontend/src/shared/generate-sidebar-entities-query-variables.tsx Generates variables for summarizeEntities instead of querying a 1-item page.
apps/hash-frontend/src/shared/draft-entities-count-context.tsx Switches draft counting to summarizeEntities.
apps/hash-frontend/src/pages/shared/entities-visualizer/use-entities-visualizer-data.tsx Splits visualizer data loading into subgraph query + summary count query.
apps/hash-frontend/src/pages/shared/entities-visualizer/shared/use-available-types.ts Uses summary typeIds/typeTitles instead of subgraph query for facets.
apps/hash-frontend/src/pages/index.page/waitlisted.tsx Uses summary count to determine whether a prospective user submission exists.
apps/hash-frontend/src/graphql/queries/knowledge/entity.queries.ts Replaces countEntities GraphQL query with summarizeEntities.
apps/hash-api/src/graphql/resolvers/knowledge/entity/entity.ts Replaces GraphQL resolver from countEntities to summarizeEntities.
apps/hash-api/src/graphql/resolvers/index.ts Wires summarizeEntities resolver into Query root.
apps/hash-api/src/graph/knowledge/primitive/entity.ts Replaces internal countEntities helper with summarizeEntities and includeCount.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread libs/@local/hash-backend-utils/src/flows.ts
Comment thread apps/hash-frontend/src/pages/index.page/waitlisted.tsx
Comment thread apps/hash-frontend/src/shared/draft-entities-count-context.tsx
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.72727% with 52 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.63%. Comparing base (fd129ea) to head (94b2f7c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ore/src/store/postgres/knowledge/entity/summary.rs 68.83% 24 Missing ⚠️
.../postgres-store/src/store/postgres/query/entity.rs 33.33% 8 Missing ⚠️
libs/@local/hash-backend-utils/src/flows.ts 0.00% 8 Missing ⚠️
libs/@local/graph/api/src/rest/entity.rs 0.00% 6 Missing ⚠️
...s-store/src/store/postgres/knowledge/entity/mod.rs 0.00% 3 Missing ⚠️
...s/hash-api/src/graph/knowledge/primitive/entity.ts 0.00% 2 Missing ⚠️
...i/src/graphql/resolvers/knowledge/entity/entity.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8897      +/-   ##
==========================================
+ Coverage   59.61%   59.63%   +0.02%     
==========================================
  Files        1348     1348              
  Lines      131877   131788      -89     
  Branches     5944     5943       -1     
==========================================
- Hits        78615    78592      -23     
+ Misses      52357    52292      -65     
+ Partials      905      904       -1     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.39% <ø> (ø)
apps.hash-api 0.00% <0.00%> (ø)
local.hash-backend-utils 2.81% <0.00%> (-0.01%) ⬇️
local.hash-graph-sdk 9.63% <ø> (ø)
local.hash-isomorphic-utils 0.00% <ø> (ø)

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.

- Deduplicate the summary `hits` CTE over `edition_id` instead of the entity
  identity, so the temporal axis drives the count (point-in-time → per entity,
  unbounded → per edition), matching the former `count_entities`.
- Source `typeTitles` from the edition cache's type-title array in the same
  aggregate (new `IsOfType`/`Title` query path), dropping the separate ontology
  lookup.
- Rewrite the semantic filter once in `getFlowRuns` before the concurrent
  entity/summary requests, so the embedding lookup isn't duplicated.
@vercel vercel Bot temporarily deployed to Preview – petrinaut June 23, 2026 20:35 Inactive
- Deny on a missing/zero count in `canUserReadEntity` (was failing open: an
  absent `count` granted read access).
- Tolerate NULL type titles in the summary decode (read `Option<String>`) instead
  of erroring the whole request when a type group has no title.
- Drop the fabricated `definitions` field from the TS `SummarizeEntitiesResponse`
  (the endpoint never returns it).
- Add a point-in-time summary-count assertion in `entity::update` (per-entity vs
  the existing per-edition unbounded count).
- Remove the stale `includeCount` sweep parameter from the entity-query bench
  definitions so they deserialize again.
- Fix the stale `Dimension` row-layout doc (now 5 columns) and initialise `count`
  consistently with the other requested dimensions.
Copilot AI review requested due to automatic review settings June 23, 2026 21:33
@vercel vercel Bot temporarily deployed to Preview – petrinaut June 23, 2026 21:33 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.

Pull request overview

Copilot reviewed 49 out of 49 changed files in this pull request and generated 1 comment.

Comment thread libs/@local/graph/postgres-store/tests/deletion/main.rs Outdated
`include_count: true` guarantees `count` is present, so the test helpers expect it rather than defaulting to 0 via `unwrap_or` — otherwise a regression returning `count: null` (notably where the expected count is 0) would pass unnoticed.
@vercel vercel Bot temporarily deployed to Preview – petrinaut June 23, 2026 21:50 Inactive
@TimDiekmann TimDiekmann requested a review from a team June 23, 2026 21:50
@TimDiekmann TimDiekmann enabled auto-merge June 23, 2026 21:51

@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 17b84ea. Configure here.

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.

Pull request overview

Copilot reviewed 49 out of 49 changed files in this pull request and generated 2 comments.

Comment thread libs/@local/graph/sdk/typescript/src/entity.ts
Comment thread libs/@local/graph/sdk/typescript/src/entity.ts
@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 $$31.7 \mathrm{ms} \pm 256 \mathrm{μs}\left({\color{gray}-1.157 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.99 \mathrm{ms} \pm 32.4 \mathrm{μs}\left({\color{gray}-0.916 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$15.9 \mathrm{ms} \pm 144 \mathrm{μs}\left({\color{gray}2.14 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$49.7 \mathrm{ms} \pm 475 \mathrm{μs}\left({\color{red}5.63 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$17.4 \mathrm{ms} \pm 165 \mathrm{μs}\left({\color{gray}0.796 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$29.0 \mathrm{ms} \pm 350 \mathrm{μs}\left({\color{gray}3.68 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$32.5 \mathrm{ms} \pm 236 \mathrm{μs}\left({\color{gray}-1.875 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$4.52 \mathrm{ms} \pm 45.7 \mathrm{μs}\left({\color{gray}-1.478 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$17.1 \mathrm{ms} \pm 186 \mathrm{μs}\left({\color{gray}1.98 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$4.35 \mathrm{ms} \pm 39.5 \mathrm{μs}\left({\color{gray}0.787 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.36 \mathrm{ms} \pm 26.9 \mathrm{μs}\left({\color{gray}0.069 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.93 \mathrm{ms} \pm 33.5 \mathrm{μs}\left({\color{gray}1.69 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$6.01 \mathrm{ms} \pm 49.7 \mathrm{μs}\left({\color{gray}0.345 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$4.07 \mathrm{ms} \pm 35.4 \mathrm{μs}\left({\color{gray}-1.675 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.87 \mathrm{ms} \pm 37.5 \mathrm{μs}\left({\color{gray}1.51 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$5.27 \mathrm{ms} \pm 46.9 \mathrm{μs}\left({\color{gray}1.24 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$4.07 \mathrm{ms} \pm 41.9 \mathrm{μs}\left({\color{gray}3.59 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.97 \mathrm{ms} \pm 46.7 \mathrm{μs}\left({\color{red}6.15 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.92 \mathrm{ms} \pm 22.3 \mathrm{μs}\left({\color{gray}-0.740 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.87 \mathrm{ms} \pm 31.8 \mathrm{μs}\left({\color{gray}4.94 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.92 \mathrm{ms} \pm 31.5 \mathrm{μs}\left({\color{gray}-0.648 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$3.25 \mathrm{ms} \pm 32.3 \mathrm{μs}\left({\color{gray}-1.438 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.88 \mathrm{ms} \pm 30.1 \mathrm{μs}\left({\color{gray}-4.934 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.28 \mathrm{ms} \pm 27.6 \mathrm{μs}\left({\color{gray}0.377 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.46 \mathrm{ms} \pm 32.2 \mathrm{μs}\left({\color{gray}3.14 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.17 \mathrm{ms} \pm 27.3 \mathrm{μs}\left({\color{gray}4.78 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$3.33 \mathrm{ms} \pm 27.7 \mathrm{μs}\left({\color{gray}-0.111 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.85 \mathrm{ms} \pm 40.0 \mathrm{μs}\left({\color{gray}2.10 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.42 \mathrm{ms} \pm 36.5 \mathrm{μs}\left({\color{gray}3.59 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.84 \mathrm{ms} \pm 39.8 \mathrm{μs}\left({\color{gray}0.437 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.83 \mathrm{ms} \pm 35.7 \mathrm{μs}\left({\color{gray}1.96 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.43 \mathrm{ms} \pm 32.9 \mathrm{μs}\left({\color{gray}4.52 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.88 \mathrm{ms} \pm 46.5 \mathrm{μs}\left({\color{gray}4.64 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$49.1 \mathrm{ms} \pm 380 \mathrm{μs}\left({\color{red}31.2 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$38.7 \mathrm{ms} \pm 308 \mathrm{μs}\left({\color{gray}1.40 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$42.9 \mathrm{ms} \pm 330 \mathrm{μs}\left({\color{red}5.26 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$37.5 \mathrm{ms} \pm 303 \mathrm{μs}\left({\color{gray}2.69 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$51.3 \mathrm{ms} \pm 418 \mathrm{μs}\left({\color{gray}4.08 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$57.2 \mathrm{ms} \pm 467 \mathrm{μs}\left({\color{red}42.9 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$47.2 \mathrm{ms} \pm 412 \mathrm{μs}\left({\color{gray}2.47 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$106 \mathrm{ms} \pm 749 \mathrm{μs}\left({\color{gray}3.85 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$53.9 \mathrm{ms} \pm 4.28 \mathrm{ms}\left({\color{red}40.2 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$296 \mathrm{ms} \pm 1.49 \mathrm{ms}\left({\color{lightgreen}-12.977 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$12.2 \mathrm{ms} \pm 105 \mathrm{μs}\left({\color{gray}-0.083 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$12.6 \mathrm{ms} \pm 95.0 \mathrm{μs}\left({\color{gray}2.66 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$12.3 \mathrm{ms} \pm 95.7 \mathrm{μs}\left({\color{gray}0.886 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$12.2 \mathrm{ms} \pm 101 \mathrm{μs}\left({\color{red}5.07 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$12.6 \mathrm{ms} \pm 100.0 \mathrm{μs}\left({\color{gray}2.48 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$12.4 \mathrm{ms} \pm 78.6 \mathrm{μs}\left({\color{gray}1.16 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$12.4 \mathrm{ms} \pm 106 \mathrm{μs}\left({\color{gray}2.77 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$12.7 \mathrm{ms} \pm 117 \mathrm{μs}\left({\color{gray}3.96 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$12.7 \mathrm{ms} \pm 115 \mathrm{μs}\left({\color{gray}1.12 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$13.0 \mathrm{ms} \pm 129 \mathrm{μs}\left({\color{gray}-0.167 \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 $$13.0 \mathrm{ms} \pm 105 \mathrm{μs}\left({\color{gray}2.57 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$13.0 \mathrm{ms} \pm 151 \mathrm{μs}\left({\color{gray}4.27 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$12.9 \mathrm{ms} \pm 124 \mathrm{μs}\left({\color{gray}1.79 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$13.0 \mathrm{ms} \pm 96.8 \mathrm{μs}\left({\color{gray}-0.089 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$13.0 \mathrm{ms} \pm 100 \mathrm{μs}\left({\color{gray}3.68 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$13.2 \mathrm{ms} \pm 106 \mathrm{μs}\left({\color{gray}2.70 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$13.4 \mathrm{ms} \pm 106 \mathrm{μs}\left({\color{red}7.11 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$12.9 \mathrm{ms} \pm 95.2 \mathrm{μs}\left({\color{gray}-0.931 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$12.7 \mathrm{ms} \pm 89.4 \mathrm{μs}\left({\color{gray}2.46 \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 $$9.92 \mathrm{ms} \pm 66.0 \mathrm{μs}\left({\color{gray}-0.430 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$70.3 \mathrm{ms} \pm 667 \mathrm{μs}\left({\color{gray}-4.660 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$130 \mathrm{ms} \pm 865 \mathrm{μs}\left({\color{lightgreen}-5.778 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$78.3 \mathrm{ms} \pm 692 \mathrm{μs}\left({\color{gray}-4.362 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$89.7 \mathrm{ms} \pm 770 \mathrm{μs}\left({\color{gray}-2.136 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$97.7 \mathrm{ms} \pm 789 \mathrm{μs}\left({\color{lightgreen}-5.803 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$106 \mathrm{ms} \pm 722 \mathrm{μs}\left({\color{gray}-3.510 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$54.4 \mathrm{ms} \pm 567 \mathrm{μs}\left({\color{gray}1.57 \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 $$85.0 \mathrm{ms} \pm 623 \mathrm{μs}\left({\color{gray}-4.551 \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 $$59.4 \mathrm{ms} \pm 512 \mathrm{μs}\left({\color{gray}-4.143 \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 $$70.9 \mathrm{ms} \pm 466 \mathrm{μs}\left({\color{gray}-2.377 \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 $$74.5 \mathrm{ms} \pm 482 \mathrm{μs}\left({\color{gray}-3.577 \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 $$74.6 \mathrm{ms} \pm 617 \mathrm{μs}\left({\color{gray}-2.802 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$123 \mathrm{ms} \pm 883 \mathrm{μs}\left({\color{gray}-1.367 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$135 \mathrm{ms} \pm 726 \mathrm{μs}\left({\color{gray}-1.567 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$21.8 \mathrm{ms} \pm 161 \mathrm{μs}\left({\color{gray}4.59 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$554 \mathrm{ms} \pm 1.46 \mathrm{ms}\left({\color{gray}2.69 \mathrm{\%}}\right) $$ Flame Graph

@TimDiekmann TimDiekmann requested a review from CiaranMn June 25, 2026 07:40
@TimDiekmann TimDiekmann added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit 3e96b0e Jun 25, 2026
110 checks passed
@TimDiekmann TimDiekmann deleted the t/be-619-split-entity-queries-and-entity-counting branch June 25, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-api Affects the HASH API (app) area/apps area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

4 participants