Skip to content

fix(graphql): make type-filtered objects queries use sane plans - #12662

Open
tomxey wants to merge 2 commits into
developfrom
sc-platform/fix-graphql-type-filter-timeout
Open

fix(graphql): make type-filtered objects queries use sane plans#12662
tomxey wants to merge 2 commits into
developfrom
sc-platform/fix-graphql-type-filter-timeout

Conversation

@tomxey

@tomxey tomxey commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Description of change

objects(filter: { type }) timed out on testnet for types with many objects (e.g. 0x3::staking_pool::StakedIota, 53k objects). Two fixes for this:

  • Rewrite the changed-objects exclusion from LEFT JOIN (SELECT DISTINCT ...) to NOT EXISTS, so Postgres can check each row with one index lookup instead of re-scanning all changed objects per row (same change in the balance query). - This helps in case postgres picks a bad plan, where it thinks that there are not much candidate rows, where in reality there is way more of them.
  • Add a migration raising the extended-statistics target on the object-type columns to 2500: testnet has more object types than fit in the current statistics, so rarer types got a rows=1 estimate and Postgres picked the bad plan. - This prevents postgres from picking the bad plan altogether

Links to any relevant issues

fixes #12536

How the change has been tested

  • Basic tests (linting, compilation, formatting, unit/integration tests)
  • Patch-specific tests (correctness, functionality coverage)

Measured on a staging server with a full testnet copy (921M rows in checkpointed_objects), across cursors of increasing age (= more objects changed after the viewed checkpoint), query objects(first: 3, filter: { type: "0x3::staking_pool::StakedIota" }):

cursor age(in terms of backward_history rows accumulated after it) no fix NOT EXISTS only statistics only both
~1k 3.7s 0.36s 43ms 43ms
~10k 24s 0.36s 53ms 44ms
30k–300k timeout (>30s) 0.36–0.39s 73–329ms 40–78ms
~1M 1.2s 0.41s 1.1s 101ms
~8M (cursor ~3h old) 24s 8.3s 8.6s 7.9s

The planner estimate for the StakedIota filter went from 1 row to 40,627 (actual 52,458).
The migration took 1m41s on a testnet-size table.

Infrastructure QA (only required for crates that are maintained by @iotaledger/infrastructure)

  • Synchronization of the indexer from genesis for a network including migration objects.
  • Restart of indexer synchronization locally without resetting the database.
  • Restart of indexer synchronization on a production-like database.
  • Deployment of services using Docker.
  • Verification of API backward compatibility.

Release Notes

  • GraphQL: objects(filter: { type }) no longer times out for types with many objects.

@iota-ci iota-ci added infrastructure Issues related to the Infrastructure Team sc-platform Issues related to the Smart Contract Platform group. labels Aug 13, 2026
Rewrite the consistent-view anti-join as NOT EXISTS and raise the
extended-statistics targets on the backward-diff tables, so type
filters on types with many objects no longer time out.
@tomxey
tomxey force-pushed the sc-platform/fix-graphql-type-filter-timeout branch from 46ed910 to 6635e72 Compare August 13, 2026 12:54
@tomxey tomxey self-assigned this Aug 13, 2026
@tomxey
tomxey marked this pull request as ready for review August 14, 2026 06:29
@tomxey
tomxey requested a review from a team as a code owner August 14, 2026 06:29
The old comment blamed the JOIN; the actual problem was the SELECT
DISTINCT subquery hiding the object_id condition from the planner.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

infrastructure Issues related to the Infrastructure Team sc-platform Issues related to the Smart Contract Platform group.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GraphQL: objects(filter: { type }) times out for types with many objects

4 participants