-- L15 probe (→ L16): keyset + visibility OR/EXISTS — the sort-key index is lost -- FeedKeysetIT.l15ProbeVisibilityOrBreaksKeysetIndex (seed 2000, ix_feed_items_keyset present) -- SELECT fi.id, fi.first_highlighted_at FROM feed_items fi -- WHERE (fi.visibility='PUBLIC' -- OR (fi.visibility='MENTIONED' AND EXISTS(SELECT 1 FROM feed_item_mentions m WHERE m.feed_item_id=fi.id AND m.mentioned_user_id=:me)) -- OR (fi.visibility='PRIVATE' AND fi.user_id=:me)) -- AND (fi.first_highlighted_at, fi.id) < (:cursor) -- ORDER BY fi.first_highlighted_at DESC, fi.id DESC LIMIT 20 -- 읽기 포인트: ix_feed_items_keyset(정렬키) 를 못 탄다. 대신 BitmapOr(visibility 3분기 각각 ix_feed_items_visibility_sort) -- + BitmapAnd(private = visibility ∩ user_id) + SubPlan(mentions EXISTS). bitmap 은 순서를 안 주므로 -- Sort 노드가 재등장 = keyset 의 "순서 seek, Sort 없음" 이점 소멸 → L16(UNION 분해로 각 분기를 정렬 보장 인덱스로). Limit (cost=100.32..100.34 rows=5 width=24) (actual time=0.189..0.193 rows=13 loops=1) Buffers: shared hit=26 -> Sort (cost=100.32..100.34 rows=5 width=24) (actual time=0.188..0.190 rows=13 loops=1) Sort Key: fi.first_highlighted_at DESC, fi.id DESC -> Bitmap Heap Scan on feed_items fi (actual time=0.114..0.178 rows=13 loops=1) Recheck Cond: (((visibility='PUBLIC') AND (ROW(first_highlighted_at, id) < ROW(cursor))) OR ((visibility='MENTIONED') AND (ROW(first_highlighted_at, id) < ROW(cursor))) OR ((visibility='PRIVATE') AND (ROW(first_highlighted_at, id) < ROW(cursor)) AND (user_id = :me))) Filter: ((visibility='PUBLIC') OR ((visibility='MENTIONED') AND (SubPlan 1)) OR ((visibility='PRIVATE') AND (user_id = :me))) Rows Removed by Filter: 3 -> BitmapOr (actual time=0.093..0.094 rows=0 loops=1) -> Bitmap Index Scan on ix_feed_items_visibility_sort (Index Cond: visibility='PUBLIC' AND ROW(...) < ROW(cursor)) -> Bitmap Index Scan on ix_feed_items_visibility_sort (Index Cond: visibility='MENTIONED' AND ROW(...) < ROW(cursor)) -> BitmapAnd -> Bitmap Index Scan on ix_feed_items_visibility_sort (Index Cond: visibility='PRIVATE' AND ROW(...) < ROW(cursor)) -> Bitmap Index Scan on uq_feed_items_user_page (Index Cond: user_id = :me) SubPlan 1 -> Index Only Scan using uq_feed_item_mentions on feed_item_mentions m (loops=4) Index Cond: ((feed_item_id = fi.id) AND (mentioned_user_id = :me)) Planning Time: 0.319 ms Execution Time: 0.325 ms