query plan worse after analyze - Mailing list pgsql-performance

From Jeff Frost
Subject query plan worse after analyze
Date
Msg-id 029201c807bc$f1642f60$120a0a0a@jefflap
Whole thread Raw
Responses Re: query plan worse after analyze
Re: query plan worse after analyze
List pgsql-performance
Postgresql: 8.2.4 and 8.2.5

I've run into a really strange problem.  I have a query that runs much
slower after analyze.  I load the DB, then run the query and it runs in
about 200ms.  I then analyze the DB, run the query again and it takes about
1500ms.  Before analyze it seems to choose Bitmap Heap Scan on episodes
current_episode, but after it chooses Index Scan Backward using
index_episodes_on_publish_on on episodes current_episode.  I've tried it on
two different pg servers and the results are same with default
random_page_cost and with random_page_cost = 2.  The entire DB is only 8MB
so easily fits in memory on all the test systems.  Any ideas what's going
on?  Setting enable_indexscan = 0 also yields a fast (200ms) plan, so that's
a workaround.

Here are the plans:


jeff=# explain ANALYZE   SELECT DISTINCT ON (shows.id) shows.id,
seasons.position AS alias_0 FROM shows
  LEFT OUTER JOIN images ON images.id = shows.landing_page_image_id
  LEFT OUTER JOIN seasons ON seasons.show_id = shows.id
  LEFT OUTER JOIN episodes ON episodes.season_id = seasons.id AND
episodes.publish_on = (
    SELECT MAX(current_episode.publish_on) AS publish_on FROM episodes AS
current_episode
     WHERE current_episode.publish_on IS NOT NULL AND
current_episode.publish_on <= NOW()
       AND current_episode.season_id = episodes.season_id
  )
  LEFT OUTER JOIN seasons current_seasons_shows ON
current_seasons_shows.show_id = shows.id AND seasons.position = (
    SELECT MAX(latest_unvaulted_season.position) FROM seasons AS
latest_unvaulted_season, episodes
    WHERE latest_unvaulted_season.show_id = seasons.show_id AND (
      latest_unvaulted_season.vaults_on IS NULL OR
latest_unvaulted_season.vaults_on > NOW()
    )
    AND episodes.season_id = latest_unvaulted_season.id AND
episodes.publish_on IS NOT NULL
    AND episodes.publish_on <= NOW()
  )
  LEFT OUTER JOIN episodes current_episodes_seasons ON
current_episodes_seasons.season_id = current_seasons_shows.id
  AND episodes.publish_on = (
    SELECT MAX(current_episode.publish_on) AS publish_on FROM episodes AS
current_episode
    WHERE current_episode.publish_on IS NOT NULL AND
current_episode.publish_on <= NOW()
    AND current_episode.season_id = episodes.season_id
  )
  WHERE (
    ( shows.deleted_at IS NULL OR shows.deleted_at > '2007-10-05
21:14:02.438466' )
    AND ( shows.archived_at IS NULL OR shows.archived_at > '2007-10-05
21:14:02.438559' )
  )
  AND (episodes.id IS NOT NULL AND current_seasons_shows.id IS NOT NULL)
;


QUERY PLAN

----------------------------------------------------------------------------
--------------------------------------------------
----------------------------------------------------------------------------
--------------------------------------------------
-------
 Unique  (cost=106.63..106.64 rows=1 width=8) (actual time=178.931..181.528
rows=29 loops=1)
   ->  Sort  (cost=106.63..106.64 rows=1 width=8) (actual
time=178.931..180.120 rows=6229 loops=1)
         Sort Key: shows.id
         ->  Nested Loop Left Join  (cost=2.27..106.62 rows=1 width=8)
(actual time=0.302..175.506 rows=6229 loops=1)
               Join Filter: (episodes.publish_on = (subplan))
               ->  Nested Loop Left Join  (cost=2.27..80.66 rows=1 width=24)
(actual time=0.262..21.725 rows=500 loops=1)
                     ->  Nested Loop  (cost=2.27..76.88 rows=1 width=28)
(actual time=0.221..19.641 rows=500 loops=1)
                           Join Filter: (current_seasons_shows.show_id =
shows.id)
                           ->  Nested Loop  (cost=2.27..74.55 rows=1
width=28) (actual time=0.215..10.716 rows=267 loops=1)
                                 ->  Nested Loop  (cost=0.00..45.72 rows=1
width=20) (actual time=0.164..2.593 rows=29 loops=1
)
                                       ->  Seq Scan on shows
(cost=0.00..1.51 rows=4 width=8) (actual time=0.010..0.033 rows=
33 loops=1)
                                             Filter: (((deleted_at IS NULL)
OR (deleted_at > '2007-10-05 21:14:02.438466'::tim
estamp without time zone)) AND ((archived_at IS NULL) OR (archived_at >
'2007-10-05 21:14:02.438559'::timestamp without time z
one)))
                                       ->  Index Scan using
index_seasons_on_show_id_and_position on seasons  (cost=0.00..11.0
4 rows=1 width=12) (actual time=0.076..0.076 rows=1 loops=33)
                                             Index Cond: (seasons.show_id =
shows.id)
                                             Filter: ("position" =
(subplan))
                                             SubPlan
                                               ->  Aggregate
(cost=9.26..9.27 rows=1 width=4) (actual time=0.040..0.040 rows=
1 loops=58)
                                                     ->  Nested Loop
(cost=2.27..9.25 rows=1 width=4) (actual time=0.015..0.0
36 rows=12 loops=58)
                                                           ->  Seq Scan on
seasons latest_unvaulted_season  (cost=0.00..2.03 r
ows=1 width=8) (actual time=0.004..0.009 rows=1 loops=58)
                                                                 Filter:
((show_id = $1) AND ((vaults_on IS NULL) OR (vaults_o
n > now())))
                                                           ->  Bitmap Heap
Scan on episodes  (cost=2.27..7.18 rows=3 width=4)
(actual time=0.009..0.019 rows=11 loops=62)
                                                                 Recheck
Cond: (episodes.season_id = latest_unvaulted_season.i
d)
                                                                 Filter:
((publish_on IS NOT NULL) AND (publish_on <= now()))
                                                                 ->  Bitmap
Index Scan on index_episodes_on_season_id  (cost=0
.00..2.27 rows=3 width=0) (actual time=0.005..0.005 rows=12 loops=62)
                                                                       Index
Cond: (episodes.season_id = latest_unvaulted_seas
on.id)
                                 ->  Bitmap Heap Scan on episodes
(cost=2.27..28.80 rows=3 width=12) (actual time=0.041..0.27
4 rows=9 loops=29)
                                       Recheck Cond: (episodes.season_id =
seasons.id)
                                       Filter: ((id IS NOT NULL) AND
(publish_on = (subplan)))
                                       ->  Bitmap Index Scan on
index_episodes_on_season_id  (cost=0.00..2.27 rows=3 width=0)
(actual time=0.005..0.005 rows=11 loops=29)
                                             Index Cond: (episodes.season_id
= seasons.id)
                                       SubPlan
                                         ->  Aggregate  (cost=7.20..7.21
rows=1 width=8) (actual time=0.022..0.022 rows=1 loop
s=324)
                                               ->  Bitmap Heap Scan on
episodes current_episode  (cost=2.27..7.19 rows=1 width
=8) (actual time=0.007..0.016 rows=12 loops=324)
                                                     Recheck Cond:
(season_id = $0)
                                                     Filter: ((publish_on IS
NOT NULL) AND (publish_on <= now()))
                                                     ->  Bitmap Index Scan
on index_episodes_on_season_id  (cost=0.00..2.27 ro
ws=3 width=0) (actual time=0.004..0.004 rows=12 loops=324)
                                                           Index Cond:
(season_id = $0)
                           ->  Seq Scan on seasons current_seasons_shows
(cost=0.00..1.59 rows=59 width=8) (actual time=0.002
..0.018 rows=59 loops=267)
                                 Filter: (id IS NOT NULL)
                     ->  Index Scan using images_pkey on images
(cost=0.00..3.77 rows=1 width=4) (actual time=0.003..0.003 ro
ws=1 loops=500)
                           Index Cond: (images.id =
shows.landing_page_image_id)
               ->  Index Scan using index_episodes_on_season_id on episodes
current_episodes_seasons  (cost=0.00..4.30 rows=3
width=4) (actual time=0.002..0.009 rows=12 loops=500)
                     Index Cond: (current_episodes_seasons.season_id =
current_seasons_shows.id)
               SubPlan
                 ->  Aggregate  (cost=7.20..7.21 rows=1 width=8) (actual
time=0.022..0.022 rows=1 loops=6229)
                       ->  Bitmap Heap Scan on episodes current_episode
(cost=2.27..7.19 rows=1 width=8) (actual time=0.007..
0.016 rows=13 loops=6229)
                             Recheck Cond: (season_id = $0)
                             Filter: ((publish_on IS NOT NULL) AND
(publish_on <= now()))
                             ->  Bitmap Index Scan on
index_episodes_on_season_id  (cost=0.00..2.27 rows=3 width=0) (actual ti
me=0.004..0.004 rows=13 loops=6229)
                                   Index Cond: (season_id = $0)
 Total runtime: 181.829 ms
(51 rows)


Now, analyze comes along and updates the statistics for me:

jeff=# ANALYZE ;
ANALYZE


QUERY
 PLAN

----------------------------------------------------------------------------
--------------------------------------------------
----------------------------------------------------------------------------
--------------------------------------------------
-
 Unique  (cost=0.00..1226.04 rows=1 width=8) (actual time=1.121..1472.459
rows=29 loops=1)
   ->  Nested Loop Left Join  (cost=0.00..1226.03 rows=1 width=8) (actual
time=1.120..1470.904 rows=6229 loops=1)
         Join Filter: (episodes.publish_on = (subplan))
         ->  Nested Loop Left Join  (cost=0.00..1156.52 rows=1 width=24)
(actual time=0.662..99.337 rows=500 loops=1)
               ->  Nested Loop  (cost=0.00..1155.40 rows=1 width=28) (actual
time=0.655..97.353 rows=500 loops=1)
                     Join Filter: (current_seasons_shows.show_id = shows.id)
                     ->  Nested Loop  (cost=0.00..1153.07 rows=1 width=28)
(actual time=0.652..88.459 rows=267 loops=1)
                           ->  Nested Loop  (cost=0.00..1062.02 rows=1
width=20) (actual time=0.089..3.140 rows=29 loops=1)
                                 Join Filter: (seasons.show_id = shows.id)
                                 ->  Index Scan using
index_seasons_on_show_id_and_position on seasons  (cost=0.00..1060.12 ro
ws=1 width=12) (actual time=0.065..2.466 rows=30 loops=1)
                                       Filter: ("position" = (subplan))
                                       SubPlan
                                         ->  Aggregate  (cost=17.83..17.84
rows=1 width=4) (actual time=0.039..0.040 rows=1 lo
ops=59)
                                               ->  Nested Loop
(cost=2.34..17.80 rows=11 width=4) (actual time=0.016..0.035 r
ows=12 loops=59)
                                                     ->  Seq Scan on seasons
latest_unvaulted_season  (cost=0.00..2.03 rows=1
width=8) (actual time=0.004..0.009 rows=1 loops=59)
                                                           Filter: ((show_id
= $2) AND ((vaults_on IS NULL) OR (vaults_on > no
w())))
                                                     ->  Bitmap Heap Scan on
episodes  (cost=2.34..15.62 rows=12 width=4) (act
ual time=0.009..0.017 rows=11 loops=63)
                                                           Recheck Cond:
(episodes.season_id = latest_unvaulted_season.id)
                                                           Filter:
((publish_on IS NOT NULL) AND (publish_on <= now()))
                                                           ->  Bitmap Index
Scan on index_episodes_on_season_id  (cost=0.00..2
.34 rows=12 width=0) (actual time=0.006..0.006 rows=11 loops=63)
                                                                 Index Cond:
(episodes.season_id = latest_unvaulted_season.id)
                                 ->  Seq Scan on shows  (cost=0.00..1.51
rows=31 width=8) (actual time=0.002..0.013 rows=33 lo
ops=30)
                                       Filter: (((deleted_at IS NULL) OR
(deleted_at > '2007-10-05 21:14:02.438466'::timestamp
 without time zone)) AND ((archived_at IS NULL) OR (archived_at >
'2007-10-05 21:14:02.438559'::timestamp without time zone)))
                           ->  Index Scan using index_episodes_on_season_id
on episodes  (cost=0.00..91.04 rows=1 width=12) (a
ctual time=0.466..2.936 rows=9 loops=29)
                                                           ->  Bitmap Index
Scan on index_episodes_on_season_id  (cost=0.00..2
.34 rows=12 width=0) (actual time=0.006..0.006 rows=11 loops=63)
                                                                 Index Cond:
(episodes.season_id = latest_unvaulted_season.id)
                                 ->  Seq Scan on shows  (cost=0.00..1.51
rows=31 width=8) (actual time=0.002..0.013 rows=33 lo
ops=30)
                                       Filter: (((deleted_at IS NULL) OR
(deleted_at > '2007-10-05 21:14:02.438466'::timestamp
 without time zone)) AND ((archived_at IS NULL) OR (archived_at >
'2007-10-05 21:14:02.438559'::timestamp without time zone)))
                           ->  Index Scan using index_episodes_on_season_id
on episodes  (cost=0.00..91.04 rows=1 width=12) (a
ctual time=0.466..2.936 rows=9 loops=29)
                                 Index Cond: (episodes.season_id =
seasons.id)
                                 Filter: ((id IS NOT NULL) AND (publish_on =
(subplan)))
                                 SubPlan
                                   ->  Result  (cost=5.70..5.71 rows=1
width=0) (actual time=0.261..0.261 rows=1 loops=324)
                                         InitPlan
                                           ->  Limit  (cost=0.00..5.70
rows=1 width=8) (actual time=0.259..0.260 rows=1 loops=
324)
                                                 ->  Index Scan Backward
using index_episodes_on_publish_on on episodes curren
t_episode  (cost=0.00..62.72 rows=11 width=8) (actual time=0.258..0.258
rows=1 loops=324)
                                                       Index Cond:
(publish_on <= now())
                                                       Filter: ((publish_on
IS NOT NULL) AND (season_id = $0))
                     ->  Seq Scan on seasons current_seasons_shows
(cost=0.00..1.59 rows=59 width=8) (actual time=0.002..0.01
7 rows=59 loops=267)
                           Filter: (id IS NOT NULL)
               ->  Index Scan using images_pkey on images  (cost=0.00..1.11
rows=1 width=4) (actual time=0.002..0.003 rows=1 l
oops=500)
                     Index Cond: (images.id = shows.landing_page_image_id)
         ->  Index Scan using index_episodes_on_season_id on episodes
current_episodes_seasons  (cost=0.00..0.77 rows=12 width
=4) (actual time=0.002..0.008 rows=12 loops=500)
               Index Cond: (current_episodes_seasons.season_id =
current_seasons_shows.id)
         SubPlan
           ->  Result  (cost=5.70..5.71 rows=1 width=0) (actual
time=0.218..0.218 rows=1 loops=6229)
                 InitPlan
                   ->  Limit  (cost=0.00..5.70 rows=1 width=8) (actual
time=0.217..0.217 rows=1 loops=6229)
                         ->  Index Scan Backward using
index_episodes_on_publish_on on episodes current_episode  (cost=0.00..6
2.72 rows=11 width=8) (actual time=0.216..0.216 rows=1 loops=6229)
                               Index Cond: (publish_on <= now())
                               Filter: ((publish_on IS NOT NULL) AND
(season_id = $0))
 Total runtime: 1472.613 ms
(47 rows)

set enable_indexscan = 0;


QU
ERY PLAN

----------------------------------------------------------------------------
--------------------------------------------------
----------------------------------------------------------------------------
--------------------------------------------------
-------
 Unique  (cost=1456.34..1456.35 rows=1 width=8) (actual
time=180.423..183.024 rows=29 loops=1)
   ->  Sort  (cost=1456.34..1456.35 rows=1 width=8) (actual
time=180.422..181.624 rows=6229 loops=1)
         Sort Key: shows.id
         ->  Nested Loop Left Join  (cost=3.31..1456.33 rows=1 width=8)
(actual time=0.165..177.225 rows=6229 loops=1)
               Join Filter: (episodes.publish_on = (subplan))
               ->  Nested Loop Left Join  (cost=2.92..1265.33 rows=1
width=24) (actual time=0.133..22.742 rows=500 loops=1)
                     ->  Nested Loop  (cost=2.34..1262.73 rows=1 width=28)
(actual time=0.125..20.141 rows=500 loops=1)
                           Join Filter: (current_seasons_shows.show_id =
shows.id)
                           ->  Nested Loop  (cost=2.34..1260.40 rows=1
width=28) (actual time=0.122..11.087 rows=267 loops=1)
                                 ->  Nested Loop  (cost=0.00..1056.47 rows=1
width=20) (actual time=0.087..2.966 rows=29 loops
=1)
                                       Join Filter: (seasons.show_id =
shows.id)
                                       ->  Seq Scan on seasons
(cost=0.00..1054.57 rows=1 width=12) (actual time=0.063..2.309
 rows=30 loops=1)
                                             Filter: ("position" =
(subplan))
                                             SubPlan
                                               ->  Aggregate
(cost=17.83..17.84 rows=1 width=4) (actual time=0.037..0.038 row
s=1 loops=59)
                                                     ->  Nested Loop
(cost=2.34..17.80 rows=11 width=4) (actual time=0.014..0
.033 rows=12 loops=59)
                                                           ->  Seq Scan on
seasons latest_unvaulted_season  (cost=0.00..2.03 r
ows=1 width=8) (actual time=0.004..0.009 rows=1 loops=59)
                                                                 Filter:
((show_id = $1) AND ((vaults_on IS NULL) OR (vaults_o
n > now())))
                                                           ->  Bitmap Heap
Scan on episodes  (cost=2.34..15.62 rows=12 width=4
) (actual time=0.008..0.016 rows=11 loops=63)
                                                                 Recheck
Cond: (episodes.season_id = latest_unvaulted_season.i
d)
                                                                 Filter:
((publish_on IS NOT NULL) AND (publish_on <= now()))
                                                                 ->  Bitmap
Index Scan on index_episodes_on_season_id  (cost=0
.00..2.34 rows=12 width=0) (actual time=0.005..0.005 rows=11 loops=63)
                                                                       Index
Cond: (episodes.season_id = latest_unvaulted_seas
on.id)
                                       ->  Seq Scan on shows
(cost=0.00..1.51 rows=31 width=8) (actual time=0.002..0.012 rows
=33 loops=30)
                                             Filter: (((deleted_at IS NULL)
OR (deleted_at > '2007-10-05 21:14:02.438466'::tim
estamp without time zone)) AND ((archived_at IS NULL) OR (archived_at >
'2007-10-05 21:14:02.438559'::timestamp without time z
one)))
                                 ->  Bitmap Heap Scan on episodes
(cost=2.34..203.90 rows=3 width=12) (actual time=0.041..0.2
74 rows=9 loops=29)
                                       Recheck Cond: (episodes.season_id =
seasons.id)
                                       Filter: ((id IS NOT NULL) AND
(publish_on = (subplan)))
                                       ->  Bitmap Index Scan on
index_episodes_on_season_id  (cost=0.00..2.34 rows=12 width=0)
 (actual time=0.005..0.005 rows=11 loops=29)
                                             Index Cond: (episodes.season_id
= seasons.id)
                                       SubPlan
                                         ->  Aggregate  (cost=15.68..15.69
rows=1 width=8) (actual time=0.022..0.022 rows=1 lo
ops=324)
                                               ->  Bitmap Heap Scan on
episodes current_episode  (cost=2.34..15.65 rows=11 wid
th=8) (actual time=0.007..0.016 rows=12 loops=324)
                                                     Recheck Cond:
(season_id = $0)
                                                     Filter: ((publish_on IS
NOT NULL) AND (publish_on <= now()))
                                                     ->  Bitmap Index Scan
on index_episodes_on_season_id  (cost=0.00..2.34 ro
ws=12 width=0) (actual time=0.004..0.004 rows=12 loops=324)
                                                           Index Cond:
(season_id = $0)
                           ->  Seq Scan on seasons current_seasons_shows
(cost=0.00..1.59 rows=59 width=8) (actual time=0.002
..0.018 rows=59 loops=267)
                                 Filter: (id IS NOT NULL)
                     ->  Bitmap Heap Scan on images  (cost=0.58..2.59 rows=1
width=4) (actual time=0.003..0.003 rows=1 loops=5
00)
                           Recheck Cond: (images.id =
shows.landing_page_image_id)
                           ->  Bitmap Index Scan on images_pkey
(cost=0.00..0.58 rows=1 width=0) (actual time=0.002..0.002 ro
ws=1 loops=500)
                                 Index Cond: (images.id =
shows.landing_page_image_id)
               ->  Bitmap Heap Scan on episodes current_episodes_seasons
(cost=0.39..2.51 rows=12 width=4) (actual time=0.006
..0.010 rows=12 loops=500)
                     Recheck Cond: (current_episodes_seasons.season_id =
current_seasons_shows.id)
                     ->  Bitmap Index Scan on index_episodes_on_season_id
(cost=0.00..0.39 rows=12 width=0) (actual time=0.00
4..0.004 rows=12 loops=500)
                           Index Cond: (current_episodes_seasons.season_id =
current_seasons_shows.id)
               SubPlan
                 ->  Aggregate  (cost=15.68..15.69 rows=1 width=8) (actual
time=0.022..0.022 rows=1 loops=6229)
                       ->  Bitmap Heap Scan on episodes current_episode
(cost=2.34..15.65 rows=11 width=8) (actual time=0.007
..0.016 rows=13 loops=6229)
                             Recheck Cond: (season_id = $0)
                             Filter: ((publish_on IS NOT NULL) AND
(publish_on <= now()))
                             ->  Bitmap Index Scan on
index_episodes_on_season_id  (cost=0.00..2.34 rows=12 width=0) (actual t
ime=0.004..0.004 rows=13 loops=6229)
                                   Index Cond: (season_id = $0)
 Total runtime: 183.160 ms
(55 rows)


----
Jeff Frost, Owner       <jeff@frostconsultingllc.com>
Frost Consulting, LLC   http://www.frostconsultingllc.com/
Phone: 650-780-7908     FAX: 650-649-1954




pgsql-performance by date:

Previous
From: Shane Ambler
Date:
Subject: Re: Problems with + 1 million record table
Next
From: Stephen Frost
Date:
Subject: Re: query plan worse after analyze