Skip to content

perf(zql): optimize Join processParentNode closure and spread#5608

Draft
Karavil wants to merge 1 commit intorocicorp:mainfrom
goblinshq:perf/join-optimizations
Draft

perf(zql): optimize Join processParentNode closure and spread#5608
Karavil wants to merge 1 commit intorocicorp:mainfrom
goblinshq:perf/join-optimizations

Conversation

@Karavil
Copy link
Contributor

@Karavil Karavil commented Feb 25, 2026

Note: This PR was generated by Claude (Anthropic) and has not been
reviewed by @Karavil. It is part of an upstream contribution effort from
the Goblins team.

Summary

Optimize Join#processParentNode by extracting the child stream closure to a method and skipping the object spread when parentNodeRelations is empty.

Motivation

#processParentNode is called for every parent row during join fetch and push operations. In a workload with 135 IVM pipelines, many of which involve joins with ~200 child rows per parent, this method is called tens of thousands of times per page render.

Two specific costs:

  1. Closure allocation: The current code creates a new closure inside #processParentNode on every call. Extracting the logic to a class method (#fetchChildStream) means we create a lightweight arrow function that delegates to the method, rather than a closure capturing local constraint-building logic.
  2. Object spread on empty: For leaf joins (the most common case in deep join pipelines), parentNodeRelations is an empty {}. The {...parentNodeRelations, [name]: stream} spread still allocates a new object and copies all (zero) properties. Checking emptiness with for...in and skipping the spread avoids this overhead.

Changes

  • Extract inline closure to #fetchChildStream(parentNodeRow) private method
  • Add fast path in #processParentNode: check if parentNodeRelations has any keys via for...in, skip the spread if empty

Expected Performance Impact

For leaf joins (bottom of a join chain), the spread skip avoids unnecessary object creation on every parent row. The method extraction reduces closure allocation overhead. Together, these reduce per-call overhead in the most frequently called join method.

Testing

  • All 336 existing join tests pass (fetch/push/sibling + flipped variants)

Extract inline child stream closure to a #fetchChildStream method to
reduce per-call allocation. Skip object spread of parentNodeRelations
when empty (common for leaf joins).

Part of IVM pipeline perf optimizations that reduced page freeze from
~7.7s to <1s in a production app.

* Extract #fetchChildStream(parentNodeRow) method from inline closure
* Add empty-check for parentNodeRelations before spreading
* No behavioral changes - pure optimization
@vercel
Copy link

vercel bot commented Feb 25, 2026

Someone is attempting to deploy a commit to the Rocicorp Team on Vercel.

A member of the Team first needs to authorize it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant