Skip to content

[ENG-1509] Fix /v4/fills/parentSubaccount query performance#3279

Merged
davidli1997 merged 5 commits intomainfrom
davidli/fills_endpoint
Dec 10, 2025
Merged

[ENG-1509] Fix /v4/fills/parentSubaccount query performance#3279
davidli1997 merged 5 commits intomainfrom
davidli/fills_endpoint

Conversation

@davidli1997
Copy link
Contributor

@davidli1997 davidli1997 commented Dec 10, 2025

Problem

The /v4/fills/parentSubaccountNumber endpoint was timing out for users with large fill histories. Root cause: using IN (subquery) to find fills across parent + child subaccounts caused Postgres to misestimate row counts and choose a catastrophically inefficient query plan—scanning millions of rows instead of using optimal index scans.

Why this happens:

When Postgres plans a query with IN (SELECT ...), it must estimate the subquery's cardinality before execution. For our subaccount lookup, it estimated ~314 rows when the actual result was 5.3M fills (testing with the subaccount causing the issue). This caused Postgres to:

  1. Fetch ALL fills for ALL child subaccounts
  2. Sort the entire result set
  3. Only then apply the LIMIT

With explicit UUIDs, Postgres can use "Index Scan Backward" per subaccount and stop early at the LIMIT.

Fix:

Resolve subaccount IDs to concrete UUIDs in a separate query before the main fills query, replacing the inline subquery.

Testing:

Tested on testnet indexer database (240M fills) against address dydx1qzq0dx4xjj06d4nxfx7ls53d8wru625s445mhs— with 5.3M fills in subaccount 0.
Query performance comparison using EXPLAIN ANALYZE:

Approach Execution Time Rows Scanned Pages Read
IN (subquery) 195s 5,306,867 962,324
IN (Explicit UUIDs) 280ms ~13,807 ~2,500
Screenshot 2025-12-10 at 12 21 01 PM

With the "subaccountId" IN (Explicit UUIDs) approach,
Screenshot 2025-12-10 at 12 22 09 PM

Summary by CodeRabbit

  • Refactor

    • Replaced subquery-based subaccount filtering with pre-resolved subaccount ID filtering for faster, more efficient retrieval.
  • New Features

    • Added a public subaccount ID lookup to resolve related subaccounts for a given parent.
  • Chores

    • CI workflow updated to trigger builds for an additional development branch.

✏️ Tip: You can customize this high-level summary in your review settings.

@davidli1997 davidli1997 requested a review from a team as a code owner December 10, 2025 18:45
@linear
Copy link

linear bot commented Dec 10, 2025

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

Walkthrough

Replaced a dynamic subquery-based parent-subaccount filter in the fills store with a pre-resolved array of subaccount IDs. Implemented findIdsForParentSubaccount in the subaccount store and updated imports. Also added davidli/fills_endpoint to the CI workflow push triggers.

Changes

Cohort / File(s) Summary
Subaccount store addition
indexer/packages/postgres/src/stores/subaccount-table.ts
Added exported findIdsForParentSubaccount(parentSubaccount, options): Promise<string[]> which fetches subaccounts for an address, filters by subaccountNumber % MAX_PARENT_SUBACCOUNTS === parentSubaccount.subaccountNumber, and returns matching subaccount IDs.
Fill-table filtering refactor
indexer/packages/postgres/src/stores/fill-table.ts
Replaced dynamic subquery getSubaccountQueryForParent with pre-resolved ID array from findIdsForParentSubaccount; updated imports and added comments describing performance rationale.
CI workflow trigger
.github/workflows/indexer-build-and-push-dev-staging.yml
Added branch davidli/fills_endpoint to the workflow push triggers so pushes to that branch run the indexer build & push workflow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify modulo filtering logic in findIdsForParentSubaccount matches previous subquery semantics.
  • Check call site handling of empty ID arrays and resulting SQL whereIn behavior.
  • Confirm imports updated and no residual references to getSubaccountQueryForParent.
  • Spot-check related queries for performance/regression.

Possibly related PRs

Suggested labels

indexer-postgres-improvement

Suggested reviewers

  • tqin7
  • Kefancao

Poem

🐇 I hopped through IDs with a nimble cheer,
Replaced the deep query so lookups are clear.
Parents to children, resolved in a breeze,
I nibble at latency and leave the logs pleased. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: a performance fix for the /v4/fills/parentSubaccount query.
Description check ✅ Passed The description provides detailed problem statement, root cause analysis, fix explanation, and comprehensive test results with metrics, but lacks a formal Test Plan section and Author/Reviewer Checklist as specified in the template.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch davidli/fills_endpoint

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4969d53 and ffba172.

📒 Files selected for processing (1)
  • indexer/packages/postgres/src/stores/fill-table.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • indexer/packages/postgres/src/stores/fill-table.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (56)
  • GitHub Check: test / run_command
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: call-build-ecs-service-comlink / (comlink) Check docker image build
  • GitHub Check: check-build-bazooka
  • GitHub Check: call-build-ecs-service-vulcan / (vulcan) Check docker image build
  • GitHub Check: check-build-auxo
  • GitHub Check: call-build-ecs-service-roundtable / (roundtable) Check docker image build
  • GitHub Check: call-build-ecs-service-ender / (ender) Check docker image build
  • GitHub Check: call-build-ecs-service-socks / (socks) Check docker image build
  • GitHub Check: lint
  • GitHub Check: build-and-push-testnet
  • GitHub Check: run_command
  • GitHub Check: build-and-push-mainnet
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Summary

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

subaccountNumber: number,
}): Promise<string[]> {
const result = await knexReadReplica.getConnection()
.select('id')
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a sub accounts table module that is able to help with this query, can you use that instead?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
indexer/packages/postgres/src/stores/subaccount-table.ts (1)

205-235: Parent‑subaccount helper is correct but could push filtering into SQL

The helper’s semantics look right: you resolve all subaccounts for the address, then select those whose subaccountNumber differs from the parent’s by a multiple of MAX_PARENT_SUBACCOUNTS, and return their IDs. That should preserve existing parent/child behavior while letting callers avoid the problematic IN (subquery) pattern.

Two follow‑ups to consider:

  • You currently fetch all subaccounts for the address and filter in JS. If an address ever has many subaccounts, this adds unnecessary network and app‑side work. A more scalable pattern would be to push the modulo filter into the SQL query (either via a dedicated query here or by extending findAll) so Postgres does the filtering directly.
  • For extra clarity and safety around JS’s % operator, you could make the non‑negativity explicit when computing the offset, e.g.:
    const offset = subaccount.subaccountNumber - parentSubaccount.subaccountNumber;
    return offset >= 0 && offset % MAX_PARENT_SUBACCOUNTS === 0;
    This documents the intended domain and avoids any surprises if types ever loosen.

Functionally this is good to ship; the above are performance/readability refinements you can address now or later.

.github/workflows/indexer-build-and-push-dev-staging.yml (1)

5-9: Consider whether the personal branch trigger should be temporary

Adding davidli/fills_endpoint to the push triggers is fine for developing this PR, but it will keep building and pushing images for any future pushes to a branch with this exact name. Once the feature is merged, consider removing this entry (or replacing with a more generic pattern) to avoid unexpected CI runs and image pushes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0dbcd4a and 4969d53.

📒 Files selected for processing (2)
  • .github/workflows/indexer-build-and-push-dev-staging.yml (1 hunks)
  • indexer/packages/postgres/src/stores/subaccount-table.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-15T16:00:11.304Z
Learnt from: hwray
Repo: dydxprotocol/v4-chain PR: 2551
File: protocol/x/subaccounts/keeper/subaccount.go:852-865
Timestamp: 2024-11-15T16:00:11.304Z
Learning: The function `GetCrossInsuranceFundBalance` in `protocol/x/subaccounts/keeper/subaccount.go` already existed and was just moved in this PR; changes to its error handling may be out of scope.

Applied to files:

  • indexer/packages/postgres/src/stores/subaccount-table.ts
🧬 Code graph analysis (1)
indexer/packages/postgres/src/stores/subaccount-table.ts (2)
indexer/packages/postgres/src/types/utility-types.ts (1)
  • Options (15-25)
indexer/packages/postgres/src/constants.ts (1)
  • MAX_PARENT_SUBACCOUNTS (130-130)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (56)
  • GitHub Check: test / run_command
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: call-build-ecs-service-ender / (ender) Check docker image build
  • GitHub Check: call-build-ecs-service-roundtable / (roundtable) Check docker image build
  • GitHub Check: call-build-ecs-service-vulcan / (vulcan) Check docker image build
  • GitHub Check: call-build-ecs-service-socks / (socks) Check docker image build
  • GitHub Check: call-build-ecs-service-comlink / (comlink) Check docker image build
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: check-build-auxo
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: check-build-bazooka
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: lint
  • GitHub Check: build-and-push-testnet
  • GitHub Check: build-and-push-mainnet
  • GitHub Check: run_command
  • GitHub Check: Analyze (go)
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: Summary
🔇 Additional comments (1)
indexer/packages/postgres/src/stores/subaccount-table.ts (1)

5-5: Import of MAX_PARENT_SUBACCOUNTS is appropriate

The new constant import is used below in the parent/child subaccount helper and matches existing constants usage patterns in this module.

- main
- 'release/indexer/v[0-9]+.[0-9]+.x' # e.g. release/indexer/v0.1.x
- 'release/indexer/v[0-9]+.x' # e.g. release/indexer/v1.x
- davidli/fills_endpoint
Copy link
Contributor

Choose a reason for hiding this comment

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

probably take this out before u merge

@davidli1997
Copy link
Contributor Author

https://github.com/Mergifyio backport release/indexer/v9.5.x

@mergify
Copy link
Contributor

mergify bot commented Dec 10, 2025

backport release/indexer/v9.5.x

✅ Backports have been created

Details

@davidli1997
Copy link
Contributor Author

https://github.com/Mergifyio backport release/indexer/v9.x

@mergify
Copy link
Contributor

mergify bot commented Dec 10, 2025

backport release/indexer/v9.x

✅ Backports have been created

Details

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

Labels

Development

Successfully merging this pull request may close these issues.

2 participants