perf: fix notifications duplicate query and add composite index (#12110)

Database CPU utilization was spiking due to expensive notification COUNT
queries. Analysis revealed two critical issues:

1. Missing database index: Notification count queries were performing
table scans without proper indexing
2. Duplicate WHERE clauses: SQL queries contained redundant read_at IS
NULL conditions, causing unnecessary query complexity

 ### Root Cause Analysis

  The expensive queries were:
```
  -- 41.61 calls/sec with duplicate condition
  SELECT COUNT(*) FROM "notifications"
  WHERE "notifications"."user_id" = $1
    AND "notifications"."account_id" = $2
    AND "notifications"."snoozed_until" IS NULL
    AND "notifications"."read_at" IS NULL
    AND "notifications"."read_at" IS NULL  -- Duplicate!
```
This was caused by a logic error in NotificationFinder#unread_count
introduced in commit cd06b2b33 (PR #8907). The method assumed
@notifications contained all notifications, but @notifications was
already filtered to unread notifications in most cases.

###  The Default Query Flow:

1. Frontend calls: NotificationsAPI.getUnreadCount() →
/notifications/unread_count
  2. No parameters sent, so params = {}
  3. NotificationFinder setup:
    - find_all_notifications: WHERE user_id = ? AND account_id = ?
    - filter_snoozed_notifications: WHERE snoozed_until IS NULL
- filter_read_notifications: WHERE read_at IS NULL (because
type_included?('read') is false)
  4. unread_count called: Adds another WHERE read_at IS NULL
----
### Solution

  1. Added Missing Database Index
  - Index: (user_id, account_id, snoozed_until, read_at)
  2. Fixed Duplicate WHERE Clause Logic
This commit is contained in:
Vishnu Narayanan
2025-08-07 15:59:40 +05:30
committed by GitHub
parent f984d745e7
commit 462ab5241c
4 changed files with 41 additions and 6 deletions

View File

@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2025_07_22_152516) do
ActiveRecord::Schema[7.1].define(version: 2025_08_05_160307) do
# These extensions should be enabled to support this database
enable_extension "pg_stat_statements"
enable_extension "pg_trgm"
@@ -909,6 +909,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_07_22_152516) do
t.index ["last_activity_at"], name: "index_notifications_on_last_activity_at"
t.index ["primary_actor_type", "primary_actor_id"], name: "uniq_primary_actor_per_account_notifications"
t.index ["secondary_actor_type", "secondary_actor_id"], name: "uniq_secondary_actor_per_account_notifications"
t.index ["user_id", "account_id", "snoozed_until", "read_at"], name: "idx_notifications_performance"
t.index ["user_id"], name: "index_notifications_on_user_id"
end