diff --git a/api/dbv1/get_users.sql.go b/api/dbv1/get_users.sql.go index 2f9dc4e2..6b7acd60 100644 --- a/api/dbv1/get_users.sql.go +++ b/api/dbv1/get_users.sql.go @@ -99,19 +99,31 @@ SELECT is_storage_v2, creator_node_endpoint, + -- "Of the people I follow, how many also follow this user?" + -- + -- Drive the loop from my followees (always small — a few thousand at + -- most) and probe whether each follows the target user. The previous + -- shape let Postgres pick a Merge Join that walked the full follower + -- list of the target — for popular target users that's millions of + -- rows. The LIMIT 1 OFFSET 0 inside the EXISTS is the same + -- optimization fence used by the feed query: it pins the planner to + -- nested-loop semantics so the plan never flips to merge join. ( SELECT count(*) - FROM follows f - JOIN ( - SELECT followee_user_id - FROM follows mf - WHERE mf.follower_user_id = $1 - AND mf.is_delete = false - ) mf ON f.follower_user_id = mf.followee_user_id + FROM follows mf WHERE $1 > 0 - AND $1 != u.user_id -- don't compute when viewing own profile - AND f.followee_user_id = u.user_id - AND f.is_delete = false + AND $1 != u.user_id -- don't compute when viewing own profile + AND mf.follower_user_id = $1 + AND mf.is_delete = false + AND EXISTS ( + SELECT 1 FROM ( + SELECT 1 FROM follows f + WHERE f.follower_user_id = mf.followee_user_id + AND f.followee_user_id = u.user_id + AND f.is_delete = false + LIMIT 1 OFFSET 0 + ) x + ) ) AS current_user_followee_follow_count, ( diff --git a/api/dbv1/queries/get_users.sql b/api/dbv1/queries/get_users.sql index e0e709a7..d4bc41a4 100644 --- a/api/dbv1/queries/get_users.sql +++ b/api/dbv1/queries/get_users.sql @@ -83,19 +83,31 @@ SELECT is_storage_v2, creator_node_endpoint, + -- "Of the people I follow, how many also follow this user?" + -- + -- Drive the loop from my followees (always small — a few thousand at + -- most) and probe whether each follows the target user. The previous + -- shape let Postgres pick a Merge Join that walked the full follower + -- list of the target — for popular target users that's millions of + -- rows. The LIMIT 1 OFFSET 0 inside the EXISTS is the same + -- optimization fence used by the feed query: it pins the planner to + -- nested-loop semantics so the plan never flips to merge join. ( SELECT count(*) - FROM follows f - JOIN ( - SELECT followee_user_id - FROM follows mf - WHERE mf.follower_user_id = @my_id - AND mf.is_delete = false - ) mf ON f.follower_user_id = mf.followee_user_id + FROM follows mf WHERE @my_id > 0 - AND @my_id != u.user_id -- don't compute when viewing own profile - AND f.followee_user_id = u.user_id - AND f.is_delete = false + AND @my_id != u.user_id -- don't compute when viewing own profile + AND mf.follower_user_id = @my_id + AND mf.is_delete = false + AND EXISTS ( + SELECT 1 FROM ( + SELECT 1 FROM follows f + WHERE f.follower_user_id = mf.followee_user_id + AND f.followee_user_id = u.user_id + AND f.is_delete = false + LIMIT 1 OFFSET 0 + ) x + ) ) AS current_user_followee_follow_count, ( diff --git a/ddl/migrations/0197_playlists_albums_partial_idx.sql b/ddl/migrations/0197_playlists_albums_partial_idx.sql new file mode 100644 index 00000000..ecb0ab35 --- /dev/null +++ b/ddl/migrations/0197_playlists_albums_partial_idx.sql @@ -0,0 +1,21 @@ +-- Partial index covering only public, undeleted, current album playlists. +-- +-- Speeds up the album_backlink subquery in GetTracks: that subquery does +-- ~200 random `playlists_pkey` lookups per popular track to filter for +-- (is_album=true AND is_delete=false AND is_current=true) — and ~99.98% +-- of those lookups end up rejected by the filter. With this partial index +-- the planner can resolve "is this an album playlist?" without ever +-- touching the playlists heap for non-album rows. +-- +-- Size budget: ~55k matching rows × ~12 bytes ≈ 700 KB. +-- +-- NOTE: intentionally NOT wrapped in BEGIN/COMMIT so that +-- CREATE INDEX CONCURRENTLY can run without holding an ACCESS EXCLUSIVE +-- lock on playlists. IF NOT EXISTS makes the migration idempotent. + +create index concurrently if not exists idx_playlists_albums_published + on playlists (playlist_id) + where is_album = true and is_delete = false and is_current = true; + +comment on index idx_playlists_albums_published is + 'Partial index for GetTracks album_backlink subquery; lets non-album lookups skip the heap entirely.';