-- L16 (a) single OR — the naive visibility filter: BitmapOr + top-N Sort + hashed SubPlan -- FeedVisibilityIT.l16ExplainThreeWayPlanCompare (seed 2000, viewer user008) -- 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)) -- ORDER BY fi.first_highlighted_at DESC, fi.id DESC LIMIT 20 -- 읽기 포인트: seq scan 이 아니라 BitmapOr(3분기 인덱스)로 후보 1500 을 heap scan → top-N Sort(순서 손실) -- + 멘션 EXISTS 는 hashed SubPlan(후보마다 반복 아님). buffers shared hit=122. Limit (cost=224.45..224.49 rows=15 width=24) (actual time=0.713..0.716 rows=20 loops=1) Buffers: shared hit=122 -> Sort (cost=224.45..224.49 rows=15 width=24) (actual time=0.712..0.713 rows=20 loops=1) Sort Key: fi.first_highlighted_at DESC, fi.id DESC Sort Method: top-N heapsort Memory: 26kB Buffers: shared hit=122 -> Bitmap Heap Scan on feed_items fi (actual time=0.256..0.590 rows=1500 loops=1) Recheck Cond: ((visibility='PUBLIC') OR (visibility='MENTIONED') OR ((user_id=:me) AND (visibility='PRIVATE'))) Filter: ((visibility='PUBLIC') OR ((visibility='MENTIONED') AND (hashed SubPlan 2)) OR ((visibility='PRIVATE') AND (user_id=:me))) Rows Removed by Filter: 200 Buffers: shared hit=122 -> BitmapOr (actual time=0.185..0.185 rows=0 loops=1) -> Bitmap Index Scan on ix_feed_items_visibility_sort (Index Cond: visibility='PUBLIC') rows=2400 -> Bitmap Index Scan on ix_feed_items_visibility_sort (Index Cond: visibility='MENTIONED') rows=800 -> Bitmap Index Scan on ix_feed_items_private (Index Cond: user_id=:me) rows=100 SubPlan 2 -> Bitmap Heap Scan on feed_item_mentions m (Recheck Cond: mentioned_user_id=:me) rows=200 -> Bitmap Index Scan on ix_mentions_user (Index Cond: mentioned_user_id=:me) rows=200 Planning Time: 0.144 ms Execution Time: 0.808 ms