Changes between Version 16 and Version 17 of P9


Ignore:
Timestamp:
06/08/26 00:58:46 (13 days ago)
Author:
211099
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • P9

    v16 v17  
    88
    99
    10 == Scenario 1 -  Quarterly story performance
     10== Scenario 2 -  Quarterly story performance
    1111
    1212=== Without index analysis
     
    293293The indexes added for this query resulted in a dramatic improvement, reducing average execution time from 1,397.98 ms to 2.74 ms (~510x faster). After adding indexes on story_id columns across all joined tables, the planner switched from Seq Scans to Index Scans on every JOIN operation, visible in the query execution plan. The indexes are kept.
    294294
    295 == Scenario 2 — Quarterly writer performance report
     295== Scenario 3 — Quarterly writer performance report
    296296{{{
    297297EXPLAIN ANALYZE
     
    299299    SELECT
    300300        DATE_TRUNC('quarter', s.story_created_at) AS quarter,
    301         u.user_id, u.username, u.user_name, u.surname,
    302         COUNT(DISTINCT s.story_id)    AS stories_published,
     301        u.user_id,
     302        u.username,
     303        u.user_name,
     304        u.surname,
     305        COUNT(DISTINCT s.story_id) AS stories_published,
    303306        COUNT(DISTINCT ch.chapter_id) AS chapters_written,
    304307        COALESCE(SUM(ch.view_count), 0) AS total_views,
    305308        COALESCE(SUM(ch.word_count), 0) AS total_words,
    306         COUNT(DISTINCT l.user_id)     AS total_likes,
    307         COUNT(DISTINCT c.comment_id)  AS total_comments,
    308         ROUND(AVG(ch.rating), 2)      AS avg_rating
     309        COUNT(DISTINCT l.user_id) AS total_likes,
     310        COUNT(DISTINCT c.comment_id) AS total_comments,
     311        ROUND(AVG(ch.rating), 2) AS avg_rating
    309312    FROM story s
    310313    JOIN writer w  ON s.user_id  = w.user_id
    311     JOIN users u   ON w.user_id  = u.user_id
     314    JOIN users  u  ON w.user_id  = u.user_id
    312315    JOIN status st ON s.story_id = st.story_id AND st.status = 'published'
    313316    LEFT JOIN chapter ch ON s.story_id = ch.story_id
     
    345348=== Analysis without indexes:
    346349{{{
    347 |QUERY PLAN                                                                                                                                                                                                |
    348 |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
    349 |Sort  (cost=295447.54..295697.57 rows=100011 width=1144) (actual time=380.965..380.977 rows=14 loops=1)                                                                                                   |
    350 |  Sort Key: with_growth.quarter DESC, (rank() OVER (?))                                                                                                                                                   |
    351 |  Sort Method: quicksort  Memory: 26kB                                                                                                                                                                    |
    352 |  ->  WindowAgg  (cost=185071.50..187321.72 rows=100011 width=1144) (actual time=380.907..380.958 rows=14 loops=1)                                                                                        |
    353 |        ->  Sort  (cost=185071.48..185321.50 rows=100011 width=1104) (actual time=380.856..380.868 rows=14 loops=1)                                                                                       |
    354 |              Sort Key: with_growth.quarter, with_growth.total_views DESC                                                                                                                                 |
    355 |              Sort Method: quicksort  Memory: 26kB                                                                                                                                                        |
    356 |              ->  Subquery Scan on with_growth  (cost=28996.63..80361.66 rows=100011 width=1104) (actual time=160.911..380.850 rows=14 loops=1)                                                           |
    357 |                    ->  WindowAgg  (cost=28996.63..79361.55 rows=100011 width=1132) (actual time=160.905..380.839 rows=14 loops=1)                                                                        |
    358 |                          ->  GroupAggregate  (cost=28995.22..73860.95 rows=100011 width=1044) (actual time=160.788..380.735 rows=14 loops=1)                                                             |
    359 |                                Group Key: u.user_id, (date_trunc('quarter'::text, s.story_created_at))                                                                                                   |
    360 |                                ->  Incremental Sort  (cost=28995.22..69860.51 rows=100011 width=994) (actual time=160.712..342.505 rows=110218 loops=1)                                                  |
    361 |                                      Sort Key: u.user_id, (date_trunc('quarter'::text, s.story_created_at)), s.story_id                                                                                  |
    362 |                                      Presorted Key: u.user_id                                                                                                                                            |
    363 |                                      Full-sort Groups: 3  Sort Method: quicksort  Average Memory: 30kB  Peak Memory: 30kB                                                                                |
    364 |                                      Pre-sorted Groups: 2  Sort Methods: quicksort, external merge  Average Memory: 13kB  Peak Memory: 26kB  Average Disk: 3760kB  Peak Disk: 7520kB                     |
    365 |                                      ->  Merge Join  (cost=15790.20..17540.59 rows=100011 width=994) (actual time=160.635..229.966 rows=110218 loops=1)                                                  |
    366 |                                            Merge Cond: (s.user_id = u.user_id)                                                                                                                           |
    367 |                                            ->  Sort  (cost=15778.73..16028.76 rows=100011 width=46) (actual time=160.547..175.009 rows=110218 loops=1)                                                   |
    368 |                                                  Sort Key: s.user_id                                                                                                                                     |
    369 |                                                  Sort Method: external merge  Disk: 4504kB                                                                                                               |
    370 |                                                  ->  Hash Right Join  (cost=1082.66..4392.92 rows=100011 width=46) (actual time=74.630..114.895 rows=110218 loops=1)                                     |
    371 |                                                        Hash Cond: (c.story_id = s.story_id)                                                                                                              |
    372 |                                                        ->  Seq Scan on comment c  (cost=0.00..1935.11 rows=100011 width=8) (actual time=0.011..8.173 rows=100011 loops=1)                                |
    373 |                                                        ->  Hash  (cost=957.59..957.59 rows=10005 width=42) (actual time=74.569..74.577 rows=10145 loops=1)                                               |
    374 |                                                              Buckets: 16384  Batches: 1  Memory Usage: 726kB                                                                                             |
    375 |                                                              ->  Hash Left Join  (cost=812.87..957.59 rows=10005 width=42) (actual time=64.682..71.998 rows=10145 loops=1)                               |
    376 |                                                                    Hash Cond: (s.story_id = l.story_id)                                                                                                  |
    377 |                                                                    ->  Hash Join  (cost=811.44..868.43 rows=10005 width=38) (actual time=64.638..70.028 rows=10111 loops=1)                              |
    378 |                                                                          Hash Cond: (s.story_id = st.story_id)                                                                                           |
    379 |                                                                          ->  Hash Join  (cost=416.49..447.21 rows=10005 width=38) (actual time=3.787..7.183 rows=10111 loops=1)                          |
    380 |                                                                                Hash Cond: (s.user_id = w.user_id)                                                                                        |
    381 |                                                                                ->  Hash Right Join  (cost=349.11..353.53 rows=10005 width=34) (actual time=3.736..5.286 rows=10111 loops=1)              |
    382 |                                                                                      Hash Cond: (ch.story_id = s.story_id)                                                                               |
    383 |                                                                                      ->  Seq Scan on chapter ch  (cost=0.00..4.12 rows=112 width=22) (actual time=0.012..0.030 rows=112 loops=1)         |
    384 |                                                                                      ->  Hash  (cost=224.05..224.05 rows=10005 width=16) (actual time=3.677..3.678 rows=10005 loops=1)                   |
    385 |                                                                                            Buckets: 16384  Batches: 1  Memory Usage: 597kB                                                               |
    386 |                                                                                            ->  Seq Scan on story s  (cost=0.00..224.05 rows=10005 width=16) (actual time=0.017..1.823 rows=10005 loops=1)|
    387 |                                                                                ->  Hash  (cost=35.50..35.50 rows=2550 width=4) (actual time=0.025..0.026 rows=5 loops=1)                                 |
    388 |                                                                                      Buckets: 4096  Batches: 1  Memory Usage: 33kB                                                                       |
    389 |                                                                                      ->  Seq Scan on writer w  (cost=0.00..35.50 rows=2550 width=4) (actual time=0.010..0.012 rows=5 loops=1)            |
    390 |                                                                          ->  Hash  (cost=269.89..269.89 rows=10005 width=4) (actual time=60.813..60.813 rows=10005 loops=1)                              |
    391 |                                                                                Buckets: 16384  Batches: 1  Memory Usage: 480kB                                                                           |
    392 |                                                                                ->  Seq Scan on status st  (cost=0.00..269.89 rows=10005 width=4) (actual time=57.194..59.348 rows=10005 loops=1)         |
    393 |                                                                                      Filter: ((status)::text = 'published'::text)                                                                        |
    394 |                                                                                      Rows Removed by Filter: 5026                                                                                        |
    395 |                                                                    ->  Hash  (cost=1.19..1.19 rows=19 width=8) (actual time=0.024..0.025 rows=19 loops=1)                                                |
    396 |                                                                          Buckets: 1024  Batches: 1  Memory Usage: 9kB                                                                                    |
    397 |                                                                          ->  Seq Scan on likes l  (cost=0.00..1.19 rows=19 width=8) (actual time=0.012..0.015 rows=19 loops=1)                           |
    398 |                                            ->  Sort  (cost=11.46..11.56 rows=40 width=956) (actual time=0.043..0.044 rows=9 loops=1)                                                                     |
    399 |                                                  Sort Key: u.user_id                                                                                                                                     |
    400 |                                                  Sort Method: quicksort  Memory: 25kB                                                                                                                    |
    401 |                                                  ->  Seq Scan on users u  (cost=0.00..10.40 rows=40 width=956) (actual time=0.022..0.025 rows=10 loops=1)                                                |
    402 |Planning Time: 4.139 ms                                                                                                                                                                                   |
    403 |JIT:                                                                                                                                                                                                      |
    404 |  Functions: 75                                                                                                                                                                                           |
    405 |  Options: Inlining false, Optimization false, Expressions true, Deforming true                                                                                                                           |
    406 |  Timing: Generation 5.977 ms (Deform 3.329 ms), Inlining 0.000 ms, Optimization 2.386 ms, Emission 55.005 ms, Total 63.368 ms                                                                            |
    407 |Execution Time: 390.828 ms                                                                                                                                                                                |
     350|QUERY PLAN                                                                                                                                                                                                   |
     351|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
     352|Sort  (cost=95.36..95.54 rows=70 width=1144) (actual time=0.465..0.469 rows=4 loops=1)                                                                                                                       |
     353|  Sort Key: with_growth.quarter DESC, (rank() OVER (?))                                                                                                                                                      |
     354|  Sort Method: quicksort  Memory: 25kB                                                                                                                                                                       |
     355|  ->  WindowAgg  (cost=91.64..93.22 rows=70 width=1144) (actual time=0.449..0.460 rows=4 loops=1)                                                                                                            |
     356|        ->  Sort  (cost=91.64..91.82 rows=70 width=1104) (actual time=0.438..0.442 rows=4 loops=1)                                                                                                           |
     357|              Sort Key: with_growth.quarter, with_growth.total_views DESC                                                                                                                                    |
     358|              Sort Method: quicksort  Memory: 25kB                                                                                                                                                           |
     359|              ->  Subquery Scan on with_growth  (cost=84.77..89.50 rows=70 width=1104) (actual time=0.420..0.435 rows=4 loops=1)                                                                             |
     360|                    ->  WindowAgg  (cost=84.77..88.80 rows=70 width=1132) (actual time=0.419..0.432 rows=4 loops=1)                                                                                          |
     361|                          ->  Sort  (cost=84.77..84.95 rows=70 width=1044) (actual time=0.411..0.414 rows=4 loops=1)                                                                                         |
     362|                                Sort Key: u.user_id, (date_trunc('quarter'::text, s.story_created_at))                                                                                                       |
     363|                                Sort Method: quicksort  Memory: 25kB                                                                                                                                         |
     364|                                ->  GroupAggregate  (cost=79.65..82.63 rows=70 width=1044) (actual time=0.349..0.407 rows=4 loops=1)                                                                         |
     365|                                      Group Key: (date_trunc('quarter'::text, s.story_created_at)), u.user_id                                                                                                |
     366|                                      ->  Sort  (cost=79.65..79.83 rows=70 width=995) (actual time=0.291..0.300 rows=118 loops=1)                                                                            |
     367|                                            Sort Key: (date_trunc('quarter'::text, s.story_created_at)), u.user_id, s.story_id                                                                               |
     368|                                            Sort Method: quicksort  Memory: 35kB                                                                                                                             |
     369|                                            ->  Merge Left Join  (cost=0.98..77.51 rows=70 width=995) (actual time=0.082..0.231 rows=118 loops=1)                                                            |
     370|                                                  Merge Cond: (s.story_id = l.story_id)                                                                                                                      |
     371|                                                  ->  Merge Left Join  (cost=0.84..63.80 rows=20 width=991) (actual time=0.066..0.141 rows=26 loops=1)                                                       |
     372|                                                        Merge Cond: (s.story_id = ch.story_id)                                                                                                               |
     373|                                                        ->  Nested Loop Left Join  (cost=0.71..50.17 rows=9 width=972) (actual time=0.052..0.088 rows=10 loops=1)                                            |
     374|                                                              ->  Nested Loop  (cost=0.57..39.81 rows=4 width=968) (actual time=0.043..0.069 rows=4 loops=1)                                                 |
     375|                                                                    Join Filter: (s.user_id = u.user_id)                                                                                                     |
     376|                                                                    ->  Nested Loop  (cost=0.43..39.06 rows=4 width=20) (actual time=0.035..0.054 rows=4 loops=1)                                            |
     377|                                                                          ->  Nested Loop  (cost=0.27..22.80 rows=4 width=16) (actual time=0.020..0.030 rows=4 loops=1)                                      |
     378|                                                                                ->  Index Only Scan using status_pk on status st  (cost=0.13..12.21 rows=4 width=4) (actual time=0.010..0.012 rows=4 loops=1)|
     379|                                                                                      Index Cond: (status = 'published'::text)                                                                               |
     380|                                                                                      Heap Fetches: 4                                                                                                        |
     381|                                                                                ->  Index Scan using story_pkey on story s  (cost=0.13..3.15 rows=1 width=16) (actual time=0.002..0.002 rows=1 loops=4)      |
     382|                                                                                      Index Cond: (story_id = st.story_id)                                                                                   |
     383|                                                                          ->  Memoize  (cost=0.17..4.98 rows=1 width=4) (actual time=0.005..0.005 rows=1 loops=4)                                            |
     384|                                                                                Cache Key: s.user_id                                                                                                         |
     385|                                                                                Cache Mode: logical                                                                                                          |
     386|                                                                                Hits: 1  Misses: 3  Evictions: 0  Overflows: 0  Memory Usage: 1kB                                                            |
     387|                                                                                ->  Index Only Scan using writer_pkey on writer w  (cost=0.15..4.97 rows=1 width=4) (actual time=0.004..0.004 rows=1 loops=3)|
     388|                                                                                      Index Cond: (user_id = s.user_id)                                                                                      |
     389|                                                                                      Heap Fetches: 3                                                                                                        |
     390|                                                                    ->  Index Scan using users_pkey on users u  (cost=0.14..0.18 rows=1 width=956) (actual time=0.003..0.003 rows=1 loops=4)                 |
     391|                                                                          Index Cond: (user_id = w.user_id)                                                                                                  |
     392|                                                              ->  Index Scan using idx_comment_story_id on comment c  (cost=0.14..2.57 rows=2 width=8) (actual time=0.003..0.004 rows=2 loops=4)             |
     393|                                                                    Index Cond: (story_id = s.story_id)                                                                                                      |
     394|                                                        ->  Materialize  (cost=0.14..13.33 rows=11 width=23) (actual time=0.010..0.038 rows=27 loops=1)                                                      |
     395|                                                              ->  Index Scan using idx_chapter_story_id on chapter ch  (cost=0.14..13.30 rows=11 width=23) (actual time=0.007..0.029 rows=11 loops=1)        |
     396|                                                  ->  Materialize  (cost=0.14..12.45 rows=18 width=8) (actual time=0.008..0.021 rows=119 loops=1)                                                            |
     397|                                                        ->  Index Scan using idx_likes_story_id on likes l  (cost=0.14..12.41 rows=18 width=8) (actual time=0.007..0.012 rows=18 loops=1)                    |
     398|Planning Time: 2.783 ms                                                                                                                                                                                      |
     399|Execution Time: 0.636 ms   
    408400}}}
    409401=== We create indexes
    410402{{{
    411 CREATE INDEX idx_story_quarter
    412     ON story(story_created_at, user_id, story_id);
     403CREATE INDEX idx_story_user_id_created ON story(user_id, story_created_at);
     404CREATE INDEX idx_status_published      ON status(story_id) WHERE status = 'published';
    413405
    414406ANALYZE story;
     
    416408ANALYZE chapter;
    417409ANALYZE likes;
    418 ANALYZE comment; 
     410ANALYZE comment;
    419411}}}
    420412=== After indexes we get:
    421413{{{
    422 |QUERY PLAN                                                                                                                                                                                                |
    423 |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
    424 |Sort  (cost=295447.54..295697.57 rows=100011 width=1144) (actual time=385.005..385.018 rows=14 loops=1)                                                                                                   |
    425 |  Sort Key: with_growth.quarter DESC, (rank() OVER (?))                                                                                                                                                   |
    426 |  Sort Method: quicksort  Memory: 26kB                                                                                                                                                                    |
    427 |  ->  WindowAgg  (cost=185071.50..187321.72 rows=100011 width=1144) (actual time=384.949..384.998 rows=14 loops=1)                                                                                        |
    428 |        ->  Sort  (cost=185071.48..185321.50 rows=100011 width=1104) (actual time=384.909..384.921 rows=14 loops=1)                                                                                       |
    429 |              Sort Key: with_growth.quarter, with_growth.total_views DESC                                                                                                                                 |
    430 |              Sort Method: quicksort  Memory: 26kB                                                                                                                                                        |
    431 |              ->  Subquery Scan on with_growth  (cost=28996.63..80361.66 rows=100011 width=1104) (actual time=164.271..384.904 rows=14 loops=1)                                                           |
    432 |                    ->  WindowAgg  (cost=28996.63..79361.55 rows=100011 width=1132) (actual time=164.265..384.892 rows=14 loops=1)                                                                        |
    433 |                          ->  GroupAggregate  (cost=28995.22..73860.95 rows=100011 width=1044) (actual time=164.169..384.779 rows=14 loops=1)                                                             |
    434 |                                Group Key: u.user_id, (date_trunc('quarter'::text, s.story_created_at))                                                                                                   |
    435 |                                ->  Incremental Sort  (cost=28995.22..69860.51 rows=100011 width=994) (actual time=164.095..346.459 rows=110218 loops=1)                                                  |
    436 |                                      Sort Key: u.user_id, (date_trunc('quarter'::text, s.story_created_at)), s.story_id                                                                                  |
    437 |                                      Presorted Key: u.user_id                                                                                                                                            |
    438 |                                      Full-sort Groups: 3  Sort Method: quicksort  Average Memory: 30kB  Peak Memory: 30kB                                                                                |
    439 |                                      Pre-sorted Groups: 2  Sort Methods: quicksort, external merge  Average Memory: 13kB  Peak Memory: 26kB  Average Disk: 3760kB  Peak Disk: 7520kB                     |
    440 |                                      ->  Merge Join  (cost=15790.20..17540.59 rows=100011 width=994) (actual time=164.019..233.324 rows=110218 loops=1)                                                  |
    441 |                                            Merge Cond: (s.user_id = u.user_id)                                                                                                                           |
    442 |                                            ->  Sort  (cost=15778.73..16028.76 rows=100011 width=46) (actual time=163.944..178.489 rows=110218 loops=1)                                                   |
    443 |                                                  Sort Key: s.user_id                                                                                                                                     |
    444 |                                                  Sort Method: external merge  Disk: 4504kB                                                                                                               |
    445 |                                                  ->  Hash Right Join  (cost=1082.66..4392.92 rows=100011 width=46) (actual time=76.636..117.141 rows=110218 loops=1)                                     |
    446 |                                                        Hash Cond: (c.story_id = s.story_id)                                                                                                              |
    447 |                                                        ->  Seq Scan on comment c  (cost=0.00..1935.11 rows=100011 width=8) (actual time=0.010..8.251 rows=100011 loops=1)                                |
    448 |                                                        ->  Hash  (cost=957.59..957.59 rows=10005 width=42) (actual time=76.575..76.583 rows=10145 loops=1)                                               |
    449 |                                                              Buckets: 16384  Batches: 1  Memory Usage: 726kB                                                                                             |
    450 |                                                              ->  Hash Left Join  (cost=812.87..957.59 rows=10005 width=42) (actual time=66.657..73.978 rows=10145 loops=1)                               |
    451 |                                                                    Hash Cond: (s.story_id = l.story_id)                                                                                                  |
    452 |                                                                    ->  Hash Join  (cost=811.44..868.43 rows=10005 width=38) (actual time=66.611..71.975 rows=10111 loops=1)                              |
    453 |                                                                          Hash Cond: (s.story_id = st.story_id)                                                                                           |
    454 |                                                                          ->  Hash Join  (cost=416.49..447.21 rows=10005 width=38) (actual time=3.840..7.192 rows=10111 loops=1)                          |
    455 |                                                                                Hash Cond: (s.user_id = w.user_id)                                                                                        |
    456 |                                                                                ->  Hash Right Join  (cost=349.11..353.53 rows=10005 width=34) (actual time=3.785..5.305 rows=10111 loops=1)              |
    457 |                                                                                      Hash Cond: (ch.story_id = s.story_id)                                                                               |
    458 |                                                                                      ->  Seq Scan on chapter ch  (cost=0.00..4.12 rows=112 width=22) (actual time=0.011..0.028 rows=112 loops=1)         |
    459 |                                                                                      ->  Hash  (cost=224.05..224.05 rows=10005 width=16) (actual time=3.725..3.726 rows=10005 loops=1)                   |
    460 |                                                                                            Buckets: 16384  Batches: 1  Memory Usage: 597kB                                                               |
    461 |                                                                                            ->  Seq Scan on story s  (cost=0.00..224.05 rows=10005 width=16) (actual time=0.018..1.860 rows=10005 loops=1)|
    462 |                                                                                ->  Hash  (cost=35.50..35.50 rows=2550 width=4) (actual time=0.029..0.030 rows=5 loops=1)                                 |
    463 |                                                                                      Buckets: 4096  Batches: 1  Memory Usage: 33kB                                                                       |
    464 |                                                                                      ->  Seq Scan on writer w  (cost=0.00..35.50 rows=2550 width=4) (actual time=0.012..0.013 rows=5 loops=1)            |
    465 |                                                                          ->  Hash  (cost=269.89..269.89 rows=10005 width=4) (actual time=62.733..62.734 rows=10005 loops=1)                              |
    466 |                                                                                Buckets: 16384  Batches: 1  Memory Usage: 480kB                                                                           |
    467 |                                                                                ->  Seq Scan on status st  (cost=0.00..269.89 rows=10005 width=4) (actual time=59.051..61.260 rows=10005 loops=1)         |
    468 |                                                                                      Filter: ((status)::text = 'published'::text)                                                                        |
    469 |                                                                                      Rows Removed by Filter: 5026                                                                                        |
    470 |                                                                    ->  Hash  (cost=1.19..1.19 rows=19 width=8) (actual time=0.025..0.026 rows=19 loops=1)                                                |
    471 |                                                                          Buckets: 1024  Batches: 1  Memory Usage: 9kB                                                                                    |
    472 |                                                                          ->  Seq Scan on likes l  (cost=0.00..1.19 rows=19 width=8) (actual time=0.012..0.016 rows=19 loops=1)                           |
    473 |                                            ->  Sort  (cost=11.46..11.56 rows=40 width=956) (actual time=0.032..0.033 rows=9 loops=1)                                                                     |
    474 |                                                  Sort Key: u.user_id                                                                                                                                     |
    475 |                                                  Sort Method: quicksort  Memory: 25kB                                                                                                                    |
    476 |                                                  ->  Seq Scan on users u  (cost=0.00..10.40 rows=40 width=956) (actual time=0.021..0.023 rows=10 loops=1)                                                |
    477 |Planning Time: 4.181 ms                                                                                                                                                                                   |
    478 |JIT:                                                                                                                                                                                                      |
    479 |  Functions: 75                                                                                                                                                                                           |
    480 |  Options: Inlining false, Optimization false, Expressions true, Deforming true                                                                                                                           |
    481 |  Timing: Generation 5.996 ms (Deform 3.374 ms), Inlining 0.000 ms, Optimization 2.381 ms, Emission 56.875 ms, Total 65.252 ms                                                                            |
    482 |Execution Time: 394.812 ms                                                                                                                                                                                |
    483 }}}
    484 Average time: 396.791 ms
    485 We conclude that the indexes added for this query provided no meaningful improvement, with execution time remaining virtually unchanged from 393 ms to 397 ms (~+1%), which is within normal measurement variance. The query plan reveals two core issues: sort operations spilling to disk (up to 7.5 MB), and several tables (chapter, likes, writer) being too small for index scans to be beneficial. The indexes are therefore not kept, as they introduce write overhead without any measurable read benefit.
    486 }}}
    487 }}}
     414|QUERY PLAN                                                                                                                                                                                                              |
     415|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
     416|Sort  (cost=95.34..95.52 rows=70 width=1144) (actual time=0.464..0.468 rows=4 loops=1)                                                                                                                                  |
     417|  Sort Key: with_growth.quarter DESC, (rank() OVER (?))                                                                                                                                                                 |
     418|  Sort Method: quicksort  Memory: 25kB                                                                                                                                                                                  |
     419|  ->  WindowAgg  (cost=91.62..93.20 rows=70 width=1144) (actual time=0.447..0.458 rows=4 loops=1)                                                                                                                       |
     420|        ->  Sort  (cost=91.62..91.80 rows=70 width=1104) (actual time=0.436..0.440 rows=4 loops=1)                                                                                                                      |
     421|              Sort Key: with_growth.quarter, with_growth.total_views DESC                                                                                                                                               |
     422|              Sort Method: quicksort  Memory: 25kB                                                                                                                                                                      |
     423|              ->  Subquery Scan on with_growth  (cost=84.75..89.48 rows=70 width=1104) (actual time=0.418..0.434 rows=4 loops=1)                                                                                        |
     424|                    ->  WindowAgg  (cost=84.75..88.78 rows=70 width=1132) (actual time=0.417..0.431 rows=4 loops=1)                                                                                                     |
     425|                          ->  Sort  (cost=84.75..84.93 rows=70 width=1044) (actual time=0.409..0.412 rows=4 loops=1)                                                                                                    |
     426|                                Sort Key: u.user_id, (date_trunc('quarter'::text, s.story_created_at))                                                                                                                  |
     427|                                Sort Method: quicksort  Memory: 25kB                                                                                                                                                    |
     428|                                ->  GroupAggregate  (cost=79.63..82.61 rows=70 width=1044) (actual time=0.348..0.406 rows=4 loops=1)                                                                                    |
     429|                                      Group Key: (date_trunc('quarter'::text, s.story_created_at)), u.user_id                                                                                                           |
     430|                                      ->  Sort  (cost=79.63..79.81 rows=70 width=995) (actual time=0.290..0.299 rows=118 loops=1)                                                                                       |
     431|                                            Sort Key: (date_trunc('quarter'::text, s.story_created_at)), u.user_id, s.story_id                                                                                          |
     432|                                            Sort Method: quicksort  Memory: 35kB                                                                                                                                        |
     433|                                            ->  Merge Left Join  (cost=0.98..77.49 rows=70 width=995) (actual time=0.100..0.233 rows=118 loops=1)                                                                       |
     434|                                                  Merge Cond: (s.story_id = l.story_id)                                                                                                                                 |
     435|                                                  ->  Merge Left Join  (cost=0.84..63.78 rows=20 width=991) (actual time=0.084..0.145 rows=26 loops=1)                                                                  |
     436|                                                        Merge Cond: (s.story_id = ch.story_id)                                                                                                                          |
     437|                                                        ->  Nested Loop Left Join  (cost=0.70..50.15 rows=9 width=972) (actual time=0.070..0.108 rows=10 loops=1)                                                       |
     438|                                                              ->  Nested Loop  (cost=0.57..39.79 rows=4 width=968) (actual time=0.060..0.087 rows=4 loops=1)                                                            |
     439|                                                                    Join Filter: (s.user_id = u.user_id)                                                                                                                |
     440|                                                                    ->  Nested Loop  (cost=0.43..39.04 rows=4 width=20) (actual time=0.052..0.071 rows=4 loops=1)                                                       |
     441|                                                                          ->  Nested Loop  (cost=0.26..22.78 rows=4 width=16) (actual time=0.019..0.029 rows=4 loops=1)                                                 |
     442|                                                                                ->  Index Only Scan using idx_status_published on status st  (cost=0.13..12.19 rows=4 width=4) (actual time=0.009..0.011 rows=4 loops=1)|
     443|                                                                                      Heap Fetches: 4                                                                                                                   |
     444|                                                                                ->  Index Scan using story_pkey on story s  (cost=0.13..3.15 rows=1 width=16) (actual time=0.002..0.002 rows=1 loops=4)                 |
     445|                                                                                      Index Cond: (story_id = st.story_id)                                                                                              |
     446|                                                                          ->  Memoize  (cost=0.17..4.98 rows=1 width=4) (actual time=0.009..0.009 rows=1 loops=4)                                                       |
     447|                                                                                Cache Key: s.user_id                                                                                                                    |
     448|                                                                                Cache Mode: logical                                                                                                                     |
     449|                                                                                Hits: 1  Misses: 3  Evictions: 0  Overflows: 0  Memory Usage: 1kB                                                                       |
     450|                                                                                ->  Index Only Scan using writer_pkey on writer w  (cost=0.15..4.97 rows=1 width=4) (actual time=0.010..0.010 rows=1 loops=3)           |
     451|                                                                                      Index Cond: (user_id = s.user_id)                                                                                                 |
     452|                                                                                      Heap Fetches: 3                                                                                                                   |
     453|                                                                    ->  Index Scan using users_pkey on users u  (cost=0.14..0.18 rows=1 width=956) (actual time=0.003..0.003 rows=1 loops=4)                            |
     454|                                                                          Index Cond: (user_id = w.user_id)                                                                                                             |
     455|                                                              ->  Index Scan using idx_comment_story_id on comment c  (cost=0.14..2.57 rows=2 width=8) (actual time=0.003..0.004 rows=2 loops=4)                        |
     456|                                                                    Index Cond: (story_id = s.story_id)                                                                                                                 |
     457|                                                        ->  Materialize  (cost=0.14..13.33 rows=11 width=23) (actual time=0.010..0.022 rows=27 loops=1)                                                                 |
     458|                                                              ->  Index Scan using idx_chapter_story_id on chapter ch  (cost=0.14..13.30 rows=11 width=23) (actual time=0.007..0.012 rows=11 loops=1)                   |
     459|                                                  ->  Materialize  (cost=0.14..12.45 rows=18 width=8) (actual time=0.008..0.021 rows=119 loops=1)                                                                       |
     460|                                                        ->  Index Scan using idx_likes_story_id on likes l  (cost=0.14..12.41 rows=18 width=8) (actual time=0.007..0.011 rows=18 loops=1)                               |
     461|Planning Time: 2.858 ms                                                                                                                                                                                                 |
     462|Execution Time: 0.631 ms                                                                                                                                                                                                |                                                                                                                                                                 
     463}}}
     464Average time: 0.628 ms
     465The indexes added for this query provided no meaningful improvement, with average execution time remaining virtually unchanged from 0.649 ms to 0.628 ms (~3%), which is within normal measurement variance. The indexes are not kept.