-
Notifications
You must be signed in to change notification settings - Fork 82
fix: Eliminate top DB queries — hourly_statistics MV, balance N+1, VACUUM in transaction #672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nelitow
wants to merge
8
commits into
main
Choose a base branch
from
nj/fix/db-performance-v2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
a44393e
fix: Eliminate top DB queries — replace hourly_statistics MV with agg…
nelitow 3b9040e
fix: Move hourly_statistics_agg upsert after transaction inserts
nelitow e0d4bfb
Update NewAddBlockRange.ts
nelitow aea65d5
Merge branch 'main' into nj/fix/db-performance-v2
nelitow ca7dab1
Drop recent_account_transactions_mv
nelitow 8928552
Handle NULLs in hourly_statistics backfill
nelitow c6a7c27
Use unnest + LATERAL join to fetch latest balances
nelitow 23155aa
Add balance composite index and backfill hourly gas
nelitow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
44 changes: 44 additions & 0 deletions
44
packages/graphql/database/migrations/046_replace_hourly_statistics_mv_with_agg_table.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| -- Migration 046: Replace hourly_statistics MV with aggregate table | ||
| -- | ||
| -- Problem: REFRESH MATERIALIZED VIEW was the top DB query at 201,290ms latency | ||
| -- It does a full seq scan of all 24h transactions every 30 minutes. | ||
| -- | ||
| -- Solution: Incremental aggregate table updated per-batch during indexing. | ||
| -- Each batch recomputes only the affected hours (typically 1-2 hours), | ||
| -- reducing cost from full 24h scan to a narrow timestamp index scan. | ||
| -- | ||
| -- Benchmark (local, 17k blocks): | ||
| -- Before: 2,132ms (full seq scan + disk sort) | ||
| -- After: ~25ms (index scan on timestamp for affected hours only) | ||
|
|
||
| -- Create the aggregate table | ||
| CREATE TABLE IF NOT EXISTS indexer.hourly_statistics_agg ( | ||
| hour TIMESTAMPTZ NOT NULL, | ||
| total_fee NUMERIC NOT NULL DEFAULT 0, | ||
| total_gas_used BIGINT NOT NULL DEFAULT 0, | ||
| PRIMARY KEY (hour) | ||
| ); | ||
|
|
||
| -- Grant read access | ||
| GRANT SELECT ON indexer.hourly_statistics_agg TO explorer_ro; | ||
|
|
||
| -- Backfill from blocks table (source of truth). | ||
| -- Avoids using the MV which had incorrect total_gas_used and could be stale | ||
| -- by up to 30 minutes (its refresh interval). | ||
| INSERT INTO indexer.hourly_statistics_agg (hour, total_fee, total_gas_used) | ||
| SELECT date_trunc('hour', timestamp), SUM(total_fee::numeric), SUM(gas_used::numeric) | ||
| FROM indexer.blocks | ||
| GROUP BY 1 | ||
| ON CONFLICT (hour) DO UPDATE | ||
| SET total_fee = excluded.total_fee, | ||
| total_gas_used = excluded.total_gas_used; | ||
|
|
||
| -- Remove the old MV refresh jobs (query strings include SET/RESET statement_timeout wrappers) | ||
| DELETE FROM indexer.database_jobs | ||
| WHERE query LIKE '%REFRESH MATERIALIZED VIEW CONCURRENTLY indexer.hourly_statistics%'; | ||
|
|
||
| DELETE FROM indexer.database_jobs | ||
| WHERE query LIKE '%ANALYZE indexer.hourly_statistics%'; | ||
|
|
||
| -- Drop the old MV | ||
| DROP MATERIALIZED VIEW IF EXISTS indexer.hourly_statistics CASCADE; |
17 changes: 17 additions & 0 deletions
17
packages/graphql/database/migrations/047_optimize_balance_index.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| -- Migration 047: Add composite index for balance lookups | ||
| -- | ||
| -- Problem: IndexBalance fetches the latest balance per (account_hash, asset_id) pair. | ||
| -- The new batched LATERAL query and the old per-pair query both use: | ||
| -- WHERE account_hash = $1 AND asset_id = $2 ORDER BY _id DESC LIMIT 1 | ||
| -- Without a composite index, PostgreSQL uses separate single-column indexes and | ||
| -- must filter/sort remaining rows, leading to excessive I/O on the 96M+ row table. | ||
| -- | ||
| -- Solution: Composite index on (account_hash, asset_id, _id DESC) so each lookup | ||
| -- becomes a single index seek returning exactly 1 row with no post-filter sort. | ||
| -- | ||
| -- Benchmark (testnet, 96M rows, 20 pairs): | ||
| -- Before (DISTINCT ON, no composite index): 36,669ms, 676K rows fetched, 101MB disk sort | ||
| -- After (LATERAL + this index): 0.3ms, 20 rows fetched, no sort | ||
|
|
||
| CREATE INDEX CONCURRENTLY IF NOT EXISTS balance_account_asset_id_idx | ||
| ON indexer.balance (account_hash, asset_id, _id DESC); |
11 changes: 11 additions & 0 deletions
11
packages/graphql/database/migrations/048_drop_unused_recent_account_transactions_mv.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| -- Migration 048: Drop unused recent_account_transactions_mv | ||
| -- | ||
| -- This MV was created in migration 030 to optimize account transaction searches. | ||
| -- It is not queried anywhere in the codebase — confirmed by grep of all source files. | ||
| -- The 4-hour refresh job scans 7 days of transactions_accounts + transactions | ||
| -- and shows up as the #3 load query in Performance Insights despite zero consumers. | ||
|
|
||
| DELETE FROM indexer.database_jobs | ||
| WHERE query LIKE '%recent_account_transactions_mv%'; | ||
|
|
||
| DROP MATERIALIZED VIEW IF EXISTS indexer.recent_account_transactions_mv CASCADE; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.