bug: notification bell scans the whole table every second - #422
Merged
Merged
Conversation
Hasura sends is_read as a query parameter, so the partial index on is_read = false cannot be matched and every evaluation falls back to a sequential scan. The table had taken 3.7 million seq scans reading 56 billion tuples to return roughly 34 rows at a time. Indexes the columns the query constrains with literals instead.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
The bell subscription asks for "unread, or read but newer than X". Hasura sends both
is_readvalues as query parameters, so the existing partial index onis_read = falsecan never be matched — the planner can't prove the predicate holds for a parameter inside an OR — and every evaluation falls back to a sequential scan.Prod state before: 3,693,139 sequential scans reading 56,000,904,973 tuples from a 28,396-row table. The subscription is 5.5% of top-level DB CPU at 14,100 buffers per call to return ~15 rows.
Verified on a synthetic table of the same shape and distribution on PG 17.11, forcing a generic plan so the parameters behave as they do in the subscription:
The index also covers the
steam_id IS NULLbranch, and is 56 kB. Migration is idempotent and tested up, down, and re-applied.Keeps
notifications_unread_steam_id_idx: the unread badge count constrainsis_readas a literal and is better served by the narrower partial index.