Skip to content

Advise Ref on high-join entities: query-time join-ceiling guard + opt-in join analysis #325

Description

@zantvoort

Selecting an entity expands its eager @FK graph into JOINs (a non-null @FK produces an INNER JOIN, a @Nullable @FK a LEFT JOIN; Ref fields are not joined and load lazily). Deep or wide entity graphs can therefore produce large join counts. Ref is exactly the lever to cut a join subtree, but nothing surfaces when a graph is getting expensive or which field would help most — new users often don't discover Ref as that lever until they hit a wall.

Non-goal (deliberate)

No pre-emptive boot/validation warning on a subjective "too many joins" threshold. A large join over indexed keys is frequently intentional and fine; a boot-time warning on an arbitrary number is noise and false positives, against the fail-fast / no-boot-warnings stance. Any advice must be objective at query time or explicitly opt-in.

Proposal — two parts

1. Query-time fail-fast on the dialect join ceiling (framework).
When a select would exceed the database's hard join limit (e.g. SQLite ~64 tables, MySQL 61), fail fast at query build with a message clearer than the raw driver error: name the entity, the join count, the limit, and the highest-win Ref field to apply. This is objective, query-time, and fail-fast — consistent with how ambiguity is already handled. Likely adds a maxJoins()-style capability to SqlDialect, defaulting to unknown/unbounded.

2. Opt-in join analysis (CLI / on-demand).
A storm analyze (or doctor) command over the compile-time metamodel index reports, per entity: the eager-select join count and a ranked list of Ref candidates by how many joins each cut would save. Zero boot noise, run on demand. Ties into the CLI work in #213. A DEBUG-level log when a real query crosses a configurable threshold is a possible third tier, off by default.

The "win" computation

Eager @FK edges form an acyclic graph rooted at the entity (eager cycles are impossible — they must already be broken with a Ref), which Storm expands into join aliases. The win of Ref-ing field f = the number of join nodes made unreachable by cutting edge f (the size of f's dominated subtree). A table reached via multiple paths is joined once per path, so path count is what is actually cut, which makes Ref-ing a shared hub especially valuable. Rank fields by win.

Notes

  • Advisory framing only ("here is the shape of your graph"), never prescriptive.
  • Prototypable locally first: pure static analysis over ModelImpl / the join builder, no database required.

Tasks

  • SqlDialect join-ceiling capability + query-time fail-fast that names the highest-win Ref field
  • Static join-graph analyzer (per-entity eager join count + ranked Ref candidates by win)
  • Expose the analysis via the storm CLI (opt-in), reusing the metamodel index
  • Docs: Ref as the join-cutting lever and when to reach for it

Metadata

Metadata

Assignees

No one assigned

    Labels

    corestorm-core and foundation workenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions