-- L14 (a) window row_number() <= 3 — cuts in the DB but scans the whole partition
-- FeedTopNIT.l14ExplainThreeWayPlanCompareIsTheCrownJewel (seed 1000, page 20, K=3)
-- SELECT t.feed_item_id, t.color, t.text, t.created_at FROM (
--   SELECT h.feed_item_id, h.color, h.text, h.created_at,
--          row_number() OVER (PARTITION BY h.feed_item_id ORDER BY h.created_at DESC) AS rn
--   FROM highlights h WHERE h.feed_item_id IN (<page-20 ids>)) t WHERE t.rn <= 3
-- 읽기 포인트: Hash Semi Join 이 페이지 부모들의 하이라이트 전량(rows=1509)을 읽고 Sort 한 뒤 WindowAgg 가
--            순번을 매긴다. PG 15+ 는 rn<=3 을 WindowAgg 의 Run Condition 으로 밀어넣지만, 파티션 정렬은
--            이미 1509행 전량을 훑는다. 반환은 60행이지만 buffers shared hit=430 (two-step 과 같다 = 같은 스캔).

Subquery Scan on t  (cost=531.52..543.16 rows=388 width=686) (actual time=1.376..1.486 rows=60 loops=1)
  Buffers: shared hit=430
  ->  WindowAgg  (cost=531.52..539.28 rows=388 width=694) (actual time=1.375..1.482 rows=60 loops=1)
        Run Condition: (row_number() OVER (?) <= 3)
        Buffers: shared hit=430
        ->  Sort  (cost=531.52..532.49 rows=388 width=686) (actual time=1.369..1.406 rows=1509 loops=1)
              Sort Key: h.feed_item_id, h.created_at DESC
              Sort Method: quicksort  Memory: 155kB
              Buffers: shared hit=430
              ->  Hash Semi Join  (cost=172.47..514.84 rows=388 width=686) (actual time=0.590..0.941 rows=1509 loops=1)
                    Hash Cond: (h.feed_item_id = "ANY_subquery".id)
                    Buffers: shared hit=430
                    ->  Seq Scan on highlights h  (cost=0.00..327.85 rows=3885 width=686) (actual time=0.289..0.421 rows=2917 loops=1)
                          Buffers: shared hit=289
                    ->  Hash  (cost=172.22..172.22 rows=20 width=16) (actual time=0.287..0.288 rows=20 loops=1)
                          Buffers: shared hit=141
                          ->  Subquery Scan on "ANY_subquery"  (cost=171.97..172.22 rows=20 width=16) (actual time=0.277..0.280 rows=20 loops=1)
                                ->  Limit  (cost=171.97..172.02 rows=20 width=24) (actual time=0.277..0.279 rows=20 loops=1)
                                      ->  Sort  (cost=171.97..174.09 rows=846 width=24) (actual time=0.276..0.277 rows=20 loops=1)
                                            Sort Key: fi.first_highlighted_at DESC, fi.id
                                            ->  Seq Scan on feed_items fi  (cost=0.00..149.46 rows=846 width=24) (actual time=0.146..0.212 rows=1000 loops=1)
Planning Time: 0.123 ms
Execution Time: 1.552 ms
