Re: Is Hash Agg being used? 7.4 seems to handle this query worse than 7.3 - Mailing list pgsql-general

From Greg Stark
Subject Re: Is Hash Agg being used? 7.4 seems to handle this query worse than 7.3
Date
Msg-id 87fzqupriy.fsf@stark.dyndns.tv
Whole thread Raw
In response to Re: Is Hash Agg being used? 7.4 seems to handle this query worse than 7.3  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Is Hash Agg being used? 7.4 seems to handle this query worse than 7.3
List pgsql-general
Tom Lane <tgl@sss.pgh.pa.us> writes:

> You could probably persuade it that hashed aggregation will be okay by
> increasing sort_mem sufficiently.  But it would also be interesting to
> see if the number-of-groups estimate can be improved ... 15122 is rather
> badly off from the true value of 31 ...

I don't see how you're ever going to reliably come up with a good estimate for
this. Consider that it's not just the distribution of the column that matters,
but the distribution given the where clauses in effect. This is dependent on
what degree the expressions in the where clauses are independent of the
expressions we're grouping on, which is hard to predict in foovance.

If the prediction is wrong is it just a performance penalty? The hash can
still proceed if it has to go to disk? In which case is there a way for me to
force it to use hashes if I know better than the optimizer?

I've run vacuum full and analyze on both databases again. The data should be
identical as I've just copied the database and I haven't updated anything. Two
example queries tested with both. It isn't using hash aggregates for either.
The plans are still quite different.


This is the previous query except I've added hier.level_0_id to the join
clause in the hopes it would skip the redundant sort. It didn't work, though
the second sort is fast due to there being relatively few records coming out
of the group.

SELECT hier.level_0_id as parent_id,
       (select localized_text from localized_text where text_id = hier.short_name_text_id and lang_code = 'en') as
name,
       *
  FROM hier LEFT OUTER JOIN (
        SELECT min(dist) AS mindist, count(distinct foo_id) AS num_foos, level_1_id, level_0_id
          FROM cache_foos JOIN foo_hier USING (foo_id)
         WHERE region_id = 839
           AND dist < 60
         GROUP BY level_0_id, level_1_id
     ) AS cache ON (hier.hier_id = cache.level_1_id and hier.level_0_id = cache.level_0_id)
 WHERE level = 1
 ORDER BY hier.level_0_id, hier.level_1_id

CVS:
                                                                                  QUERY PLAN
                                                      

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=4091.65..4091.73 rows=31 width=101) (actual time=907.95..907.99 rows=31 loops=1)
   Sort Key: hier.level_0_id, hier.level_1_id
   ->  Merge Left Join  (cost=3964.22..4090.89 rows=31 width=101) (actual time=905.53..907.61 rows=31 loops=1)
         Merge Cond: (("outer".level_0_id = "inner".level_0_id) AND ("outer".hier_id = "inner".level_1_id))
         ->  Sort  (cost=64.63..64.71 rows=31 width=77) (actual time=7.61..7.64 rows=31 loops=1)
               Sort Key: hier.level_0_id, hier.hier_id
               ->  Seq Scan on hier  (cost=0.00..63.86 rows=31 width=77) (actual time=6.47..7.36 rows=31 loops=1)
                     Filter: ("level" = 1)
         ->  Sort  (cost=3899.59..3899.90 rows=124 width=24) (actual time=897.76..897.80 rows=31 loops=1)
               Sort Key: "cache".level_0_id, "cache".level_1_id
               ->  Subquery Scan "cache"  (cost=3697.05..3895.28 rows=124 width=24) (actual time=771.57..897.28 rows=31
loops=1)
                     ->  GroupAggregate  (cost=3697.05..3895.28 rows=124 width=24) (actual time=771.55..897.03 rows=31
loops=1)
                           ->  Sort  (cost=3697.05..3736.57 rows=15809 width=24) (actual time=764.08..782.64 rows=16440
loops=1)
                                 Sort Key: foo_hier.level_0_id, foo_hier.level_1_id
                                 ->  Hash Join  (cost=853.20..2594.49 rows=15809 width=24) (actual time=307.51..603.83
rows=16440loops=1) 
                                       Hash Cond: ("outer".foo_id = "inner".foo_id)
                                       ->  Index Scan using idx_cache_foos on cache_foos  (cost=0.00..752.94 rows=15808
width=12)(actual time=0.08..111.71 rows=16486 loops=1) 
                                             Index Cond: ((region_id = 839) AND (dist < 60::double precision))
                                       ->  Hash  (cost=740.16..740.16 rows=45216 width=12) (actual time=306.11..306.11
rows=0loops=1) 
                                             ->  Seq Scan on foo_hier  (cost=0.00..740.16 rows=45216 width=12) (actual
time=0.03..143.56rows=45140 loops=1) 
         SubPlan
           ->  Index Scan using localized_text_pkey on localized_text  (cost=0.00..4.05 rows=2 width=17) (actual
time=0.03..0.03rows=1 loops=31) 
                 Index Cond: ((text_id = $0) AND (lang_code = 'en'::bpchar))
 Total runtime: 915.22 msec


7.3:
                                                                                      QUERY PLAN
                                                             

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=4056.43..4056.51 rows=31 width=101) (actual time=1036.93..1036.97 rows=31 loops=1)
   Sort Key: hier.level_0_id, hier.level_1_id
   ->  Merge Join  (cost=4047.39..4055.66 rows=31 width=101) (actual time=1034.53..1036.59 rows=31 loops=1)
         Merge Cond: (("outer".level_0_id = "inner".level_0_id) AND ("outer".hier_id = "inner".level_1_id))
         ->  Sort  (cost=64.63..64.71 rows=31 width=77) (actual time=10.15..10.18 rows=31 loops=1)
               Sort Key: hier.level_0_id, hier.hier_id
               ->  Seq Scan on hier  (cost=0.00..63.86 rows=31 width=77) (actual time=9.59..9.94 rows=31 loops=1)
                     Filter: ("level" = 1)
         ->  Sort  (cost=3982.76..3986.82 rows=1624 width=24) (actual time=1024.23..1024.26 rows=31 loops=1)
               Sort Key: "cache".level_0_id, "cache".level_1_id
               ->  Subquery Scan "cache"  (cost=3693.23..3896.18 rows=1624 width=24) (actual time=835.96..1023.98
rows=31loops=1) 
                     ->  Aggregate  (cost=3693.23..3896.18 rows=1624 width=24) (actual time=835.95..1023.76 rows=31
loops=1)
                           ->  Group  (cost=3693.23..3815.00 rows=16236 width=24) (actual time=828.96..941.70
rows=16440loops=1) 
                                 ->  Sort  (cost=3693.23..3733.82 rows=16236 width=24) (actual time=828.93..848.83
rows=16440loops=1) 
                                       Sort Key: foo_hier.level_0_id, foo_hier.level_1_id
                                       ->  Hash Join  (cost=1432.53..2557.77 rows=16236 width=24) (actual
time=350.81..670.83rows=16440 loops=1) 
                                             Hash Cond: ("outer".foo_id = "inner".foo_id)
                                             ->  Index Scan using idx_cache_foos on cache_foos  (cost=0.00..800.51
rows=16236width=12) (actual time=0.08..159.95 rows=16486 loops=1) 
                                                   Index Cond: ((region_id = 839) AND (dist < 60::double precision))
                                             ->  Hash  (cost=746.35..746.35 rows=45135 width=12) (actual
time=349.15..349.15rows=0 loops=1) 
                                                   ->  Seq Scan on foo_hier  (cost=0.00..746.35 rows=45135 width=12)
(actualtime=0.06..219.15 rows=45140 loops=1) 
         SubPlan
           ->  Index Scan using localized_text_pkey on localized_text  (cost=0.00..4.10 rows=1 width=17) (actual
time=0.03..0.03rows=1 loops=31) 
                 Index Cond: ((text_id = $0) AND (lang_code = 'en'::bpchar))
 Total runtime: 1042.86 msec





This is another query, one that involves a distinct on and a group. I guess
the plan for this one could be different because the JOIN no longer constrains
the join order. Though the order seems the same to me, it's the statistics
that seem to be different.


SELECT *
  FROM (
        SELECT DISTINCT ON (bar_id)
               bar_id, bar_location_id, num_foos, mindist
          FROM (
                SELECT bar_id, bar_location_id, count(distinct foo_id) as num_foos, min(dist) as mindist
                  FROM cache_foos
                 WHERE region_id = 839
                   AND dist < 60
                   AND foo_id is not null
                 GROUP BY bar_id, bar_location_id
                ) as x
         ORDER BY bar_id, mindist asc
      ) AS cache
   JOIN bar using (bar_id)
   JOIN bar_location using (bar_location_id)


CVS:

                                                                                           QUERY PLAN
                                                                        

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Merge Join  (cost=3438.87..3815.85 rows=200 width=654) (actual time=470.72..533.88 rows=112 loops=1)
   Merge Cond: ("outer".bar_location_id = "inner".bar_location_id)
   ->  Index Scan using bar_location_pkey on bar_location  (cost=0.00..344.50 rows=11792 width=610) (actual
time=0.04..59.41rows=11757 loops=1) 
   ->  Sort  (cost=3438.87..3439.37 rows=200 width=44) (actual time=435.51..435.68 rows=112 loops=1)
         Sort Key: "cache".bar_location_id
         ->  Merge Join  (cost=3319.28..3431.22 rows=200 width=44) (actual time=407.23..434.97 rows=112 loops=1)
               Merge Cond: ("outer".bar_id = "inner".bar_id)
               ->  Index Scan using bar_pkey on bar  (cost=0.00..99.52 rows=3768 width=20) (actual time=0.02..18.18
rows=3619loops=1) 
               ->  Sort  (cost=3319.28..3319.78 rows=200 width=20) (actual time=407.17..407.29 rows=112 loops=1)
                     Sort Key: "cache".bar_id
                     ->  Subquery Scan "cache"  (cost=3232.65..3311.64 rows=200 width=20) (actual time=405.71..406.80
rows=112loops=1) 
                           ->  Unique  (cost=3232.65..3311.64 rows=200 width=20) (actual time=405.70..406.24 rows=112
loops=1)
                                 ->  Sort  (cost=3232.65..3272.14 rows=15797 width=20) (actual time=405.69..405.84
rows=146loops=1) 
                                       Sort Key: bar_id, mindist
                                       ->  Subquery Scan x  (cost=1854.57..2131.02 rows=15797 width=20) (actual
time=272.07..405.08rows=146 loops=1) 
                                             ->  GroupAggregate  (cost=1854.57..2131.02 rows=15797 width=20) (actual
time=272.06..404.21rows=146 loops=1) 
                                                   ->  Sort  (cost=1854.57..1894.06 rows=15797 width=20) (actual
time=270.37..289.31rows=16440 loops=1) 
                                                         Sort Key: bar_id, bar_location_id
                                                         ->  Index Scan using idx_cache_foos on cache_foos
(cost=0.00..752.94rows=15797 width=20) (actual time=0.05..118.41 rows=16440 loops=1) 
                                                               Index Cond: ((region_id = 839) AND (dist < 60::double
precision))
                                                               Filter: (foo_id IS NOT NULL)
 Total runtime: 540.00 msec


7.3:
                                                                                            QUERY PLAN
                                                                         

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=2236.97..2892.88 rows=162 width=159) (actual time=515.70..562.77 rows=112 loops=1)
   ->  Merge Join  (cost=2236.97..2397.80 rows=162 width=44) (actual time=515.58..555.70 rows=112 loops=1)
         Merge Cond: ("outer".bar_id = "inner".bar_id)
         ->  Index Scan using bar_pkey on bar  (cost=0.00..148.37 rows=3850 width=20) (actual time=0.05..29.76
rows=3619loops=1) 
         ->  Sort  (cost=2236.97..2237.37 rows=162 width=20) (actual time=515.49..515.64 rows=112 loops=1)
               Sort Key: "cache".bar_id
               ->  Subquery Scan "cache"  (cost=2222.92..2231.02 rows=162 width=20) (actual time=513.96..515.09
rows=112loops=1) 
                     ->  Unique  (cost=2222.92..2231.02 rows=162 width=20) (actual time=513.95..514.51 rows=112
loops=1)
                           ->  Sort  (cost=2222.92..2226.97 rows=1621 width=20) (actual time=513.94..514.11 rows=146
loops=1)
                                 Sort Key: bar_id, mindist
                                 ->  Subquery Scan x  (cost=1933.89..2136.50 rows=1621 width=20) (actual
time=313.72..513.34rows=146 loops=1) 
                                       ->  Aggregate  (cost=1933.89..2136.50 rows=1621 width=20) (actual
time=313.71..512.52rows=146 loops=1) 
                                             ->  Group  (cost=1933.89..2055.46 rows=16209 width=20) (actual
time=311.41..422.29rows=16440 loops=1) 
                                                   ->  Sort  (cost=1933.89..1974.41 rows=16209 width=20) (actual
time=311.39..329.79rows=16440 loops=1) 
                                                         Sort Key: bar_id, bar_location_id
                                                         ->  Index Scan using idx_cache_foos on cache_foos
(cost=0.00..800.51rows=16209 width=20) (actual time=0.05..181.92 rows=16440 loops=1) 
                                                               Index Cond: ((region_id = 839) AND (dist < 60::double
precision))
                                                               Filter: (foo_id IS NOT NULL)
   ->  Index Scan using bar_location_pkey on bar_location  (cost=0.00..3.04 rows=1 width=115) (actual time=0.04..0.04
rows=1loops=112) 
         Index Cond: ("outer".bar_location_id = bar_location.bar_location_id)
 Total runtime: 568.69 msec


[BTW I've had to search and repalce on the plans at the request of the client,
 I hope I didn't lose any relevant information doing that]

--
greg

pgsql-general by date:

Previous
From: Dmitry Tkach
Date:
Subject: Re: accessing currval(), How? ... Trigger? I think...???
Next
From: "Ed L."
Date:
Subject: translating filenames into tablenames?