Обсуждение: Query performance with disabled hashjoin and mergejoin

Поиск
Список
Период
Сортировка

Query performance with disabled hashjoin and mergejoin

От
Ivan Voras
Дата:
I'm running all this on a 9.0 server with good enough hardware. The
query is:

SELECT  news.id AS news_id
                                 ,       news.layout_id
                                 ,       news.news_relation_id
                                 ,       news.author_id
                                 ,       news.date_created
                                 ,       news.date_published
                                 ,       news.lastedit
                                 ,       news.lastedit_user_id
                                 ,       news.lastedit_date
                                 ,       news.approved_by
                                 ,       news.state
                                 ,       news.visible_from
                                 ,       news.visible_to
                                 ,       news.archived_by
                                 ,       news.archived_date
                                 ,       news.priority
                                 ,       news.collection_id
                                 ,       news.comment
                                 ,       news.keywords
                                 ,       news.icon
                                 ,       news.icon_url
                                 ,       news.icon_width
                                 ,       news.icon_height
                                 ,       news.icon_position
                                 ,       news.icon_onclick
                                 ,       news.icon_newwindow
                                 ,       news.no_lead
                                 ,       news.content_exists
                                     , news.title, news.lead, news.content


                                 ,       author.public_name AS
author_public_name
                                 ,       lastedit_user.public_name AS
lastedit_user_public_name
                                 ,       approved_by_user.public_name AS
approved_by_public_name
                                 ,       archived_by_user.public_name AS
archived_by_public_name
                             FROM news
                                 JOIN users AS author ON news.author_id
= author.id
                                 LEFT JOIN users AS lastedit_user ON
news.lastedit_user_id = lastedit_user.id
                                 LEFT JOIN users AS approved_by_user ON
news.approved_by = approved_by_user.id
                                 LEFT JOIN users AS archived_by_user ON
news.archived_by = archived_by_user.id

                             WHERE (news.layout_id = 8980) AND (state =
2) AND (date_published <= 1296806570 AND (visible_from IS NULL OR
1296806570 BETWEEN visible_f
rom AND visible_to))
                             ORDER BY priority DESC, date_published DESC
;

The "vanilla" plan, with default settings is:

  Sort  (cost=7325.84..7329.39 rows=1422 width=678) (actual
time=100.846..100.852 rows=7 loops=1)
    Sort Key: news.priority, news.date_published
    Sort Method:  quicksort  Memory: 38kB
    ->  Hash Left Join  (cost=2908.02..7251.37 rows=1422 width=678)
(actual time=100.695..100.799 rows=7 loops=1)
          Hash Cond: (news.archived_by = archived_by_user.id)
          ->  Hash Left Join  (cost=2501.75..6819.47 rows=1422
width=667) (actual time=76.742..76.830 rows=7 loops=1)
                Hash Cond: (news.approved_by = approved_by_user.id)
                ->  Hash Left Join  (cost=2095.48..6377.69 rows=1422
width=656) (actual time=53.248..53.318 rows=7 loops=1)
                      Hash Cond: (news.lastedit_user_id = lastedit_user.id)
                      ->  Hash Join  (cost=1689.21..5935.87 rows=1422
width=645) (actual time=29.793..29.846 rows=7 loops=1)
                            Hash Cond: (news.author_id = author.id)
                            ->  Bitmap Heap Scan on news
(cost=1282.94..5494.05 rows=1422 width=634) (actual time=5.532..5.560
rows=7 loops=1)
                                  Recheck Cond: ((layout_id = 8980) AND
(state = 2) AND ((visible_from IS NULL) OR (1296806570 <= visible_to)))
                                  Filter: ((date_published <=
1296806570) AND ((visible_from IS NULL) OR ((1296806570 >= visible_from)
AND (1296806570 <= visible_to))))
                                  ->  BitmapAnd  (cost=1282.94..1282.94
rows=1430 width=0) (actual time=5.508..5.508 rows=0 loops=1)
                                        ->  Bitmap Index Scan on
news_index_layout_id_state  (cost=0.00..150.14 rows=2587 width=0)
(actual time=0.909..0.909 rows=3464 loops=1)
                                              Index Cond: ((layout_id =
8980) AND (state = 2))
                                        ->  BitmapOr
(cost=1132.20..1132.20 rows=20127 width=0) (actual time=4.136..4.136
rows=0 loops=1)
                                              ->  Bitmap Index Scan on
news_visible_from  (cost=0.00..1122.09 rows=19976 width=0) (actual
time=3.367..3.367 rows=19932 loops=1)
                                                    Index Cond:
(visible_from IS NULL)
                                              ->  Bitmap Index Scan on
news_visible_to  (cost=0.00..9.40 rows=151 width=0) (actual
time=0.766..0.766 rows=43 loops=1)
                                                    Index Cond:
(1296806570 <= visible_to)
                            ->  Hash  (cost=281.12..281.12 rows=10012
width=15) (actual time=24.247..24.247 rows=10012 loops=1)
                                  Buckets: 1024  Batches: 1  Memory
Usage: 482kB
                                  ->  Seq Scan on users author
(cost=0.00..281.12 rows=10012 width=15) (actual time=0.004..11.354
rows=10012 loops=1)
                      ->  Hash  (cost=281.12..281.12 rows=10012
width=15) (actual time=23.444..23.444 rows=10012 loops=1)
                            Buckets: 1024  Batches: 1  Memory Usage: 482kB
                            ->  Seq Scan on users lastedit_user
(cost=0.00..281.12 rows=10012 width=15) (actual time=0.004..10.752
rows=10012 loops=1)
                ->  Hash  (cost=281.12..281.12 rows=10012 width=15)
(actual time=23.481..23.481 rows=10012 loops=1)
                      Buckets: 1024  Batches: 1  Memory Usage: 482kB
                      ->  Seq Scan on users approved_by_user
(cost=0.00..281.12 rows=10012 width=15) (actual time=0.002..10.695
rows=10012 loops=1)
          ->  Hash  (cost=281.12..281.12 rows=10012 width=15) (actual
time=23.941..23.941 rows=10012 loops=1)
                Buckets: 1024  Batches: 1  Memory Usage: 482kB
                ->  Seq Scan on users archived_by_user
(cost=0.00..281.12 rows=10012 width=15) (actual time=0.003..10.673
rows=10012 loops=1)
  Total runtime: 101.302 ms
(35 rows)

But with these changes:

set enable_hashjoin=f;
set enable_mergejoin=f;

the plan becomes:

  Sort  (cost=9786.25..9789.87 rows=1446 width=678) (actual
time=5.408..5.414 rows=7 loops=1)
    Sort Key: news.priority, news.date_published
    Sort Method:  quicksort  Memory: 38kB
    ->  Nested Loop Left Join  (cost=439.10..9710.35 rows=1446
width=678) (actual time=5.133..5.364 rows=7 loops=1)
          ->  Nested Loop Left Join  (cost=439.10..8459.74 rows=1446
width=667) (actual time=5.128..5.330 rows=7 loops=1)
                ->  Nested Loop Left Join  (cost=439.10..7209.12
rows=1446 width=656) (actual time=5.122..5.271 rows=7 loops=1)
                      ->  Nested Loop  (cost=439.10..5958.51 rows=1446
width=645) (actual time=5.112..5.204 rows=7 loops=1)
                            ->  Bitmap Heap Scan on news
(cost=439.10..4707.89 rows=1446 width=634) (actual time=5.096..5.122
rows=7 loops=1)
                                  Recheck Cond: ((layout_id = 8980) AND
(state = 2) AND ((visible_from IS NULL) OR (1296806570 <= visible_to)))
                                  Filter: ((date_published <=
1296806570) AND ((visible_from IS NULL) OR ((1296806570 >= visible_from)
AND (1296806570 <= visible_to))))
                                  ->  BitmapAnd  (cost=439.10..439.10
rows=1455 width=0) (actual time=5.073..5.073 rows=0 loops=1)
                                        ->  Bitmap Index Scan on
news_index_layout_id_state  (cost=0.00..58.62 rows=2637 width=0) (actual
time=0.880..0.880 rows=3464 loops=1)
                                              Index Cond: ((layout_id =
8980) AND (state = 2))
                                        ->  BitmapOr
(cost=379.86..379.86 rows=20084 width=0) (actual time=3.734..3.734
rows=0 loops=1)
                                              ->  Bitmap Index Scan on
news_visible_from  (cost=0.00..373.74 rows=19932 width=0) (actual
time=3.255..3.255 rows=19932 loops=1)
                                                    Index Cond:
(visible_from IS NULL)
                                              ->  Bitmap Index Scan on
news_visible_to  (cost=0.00..5.39 rows=152 width=0) (actual
time=0.476..0.476 rows=43 loops=1)
                                                    Index Cond:
(1296806570 <= visible_to)
                            ->  Index Scan using users_pkey on users
author  (cost=0.00..0.85 rows=1 width=15) (actual time=0.006..0.007
rows=1 loops=7)
                                  Index Cond: (author.id = news.author_id)
                      ->  Index Scan using users_pkey on users
lastedit_user  (cost=0.00..0.85 rows=1 width=15) (actual
time=0.004..0.005 rows=1 loops=7)
                            Index Cond: (news.lastedit_user_id =
lastedit_user.id)
                ->  Index Scan using users_pkey on users
approved_by_user  (cost=0.00..0.85 rows=1 width=15) (actual
time=0.002..0.004 rows=1 loops=7)
                      Index Cond: (news.approved_by = approved_by_user.id)
          ->  Index Scan using users_pkey on users archived_by_user
(cost=0.00..0.85 rows=1 width=15) (actual time=0.001..0.001 rows=0 loops=7)
                Index Cond: (news.archived_by = archived_by_user.id)
  Total runtime: 5.605 ms
(27 rows)

Note the difference in execution times: 100 ms vs 5 ms.

So far, I've tried increasing statistics to 1000 on state, layout_id,
author_id, lastedit_user_id, approved_by, archived_by fields, reindexing
and vacuum analyze-ing it, but with the default settings the planner
keeps missing the mark.

The news table is:

                                       Table "public.news"
       Column      |          Type          |
Modifiers
------------------+------------------------+---------------------------------------------------
  id               | integer                | not null default
nextval('news_id_seq'::regclass)
  layout_id        | integer                | not null
  news_relation_id | integer                | not null
  author_id        | integer                | not null default 10
  date_created     | integer                | not null
  date_published   | integer                | not null
  lastedit         | boolean                | not null default false
  lastedit_user_id | integer                | not null default 10
  lastedit_date    | integer                | not null
  approved_by      | integer                | default 10
  state            | smallint               | not null
  visible_from     | integer                |
  visible_to       | integer                |
  archived_by      | integer                | default 10
  archived_date    | integer                |
  priority         | smallint               | not null default 5
  collection_id    | integer                |
  comment          | boolean                | not null default false
  keywords         | text                   | not null default ''::text
  icon             | boolean                | not null default false
  icon_url         | text                   |
  icon_width       | smallint               |
  icon_height      | smallint               |
  icon_position    | character(1)           |
  icon_onclick     | text                   |
  icon_newwindow   | boolean                |
  title            | character varying(300) | not null
  no_lead          | boolean                | not null default false
  content_exists   | boolean                | not null default false
  lead             | text                   | not null
  content          | text                   | not null default ''::text
  _fts_            | tsvector               |
Indexes:
     "news_pkey" PRIMARY KEY, btree (id)
     "news_layout_id_key" UNIQUE, btree (layout_id, news_relation_id)
     "forms_index_layout_id_state" btree (layout_id, state)
     "ii1" btree (author_id)
     "ii2" btree (lastedit_user_id)
     "ii3" btree (approved_by)
     "ii4" btree (archived_by)
     "news_fts" gin (_fts_)
     "news_index_date_published" btree (date_published)
     "news_index_lastedit" btree (lastedit_date)
     "news_index_layout_id" btree (layout_id)
     "news_index_layout_id_state" btree (layout_id, state)
     "news_index_priority" btree (priority)
     "news_visible_from" btree (visible_from)
     "news_visible_to" btree (visible_to)

Re: Query performance with disabled hashjoin and mergejoin

От
Greg Smith
Дата:
Ivan Voras wrote:
> The "vanilla" plan, with default settings is:

Pause here for a second:  why default settings?  A default PostgreSQL
configuration is suitable for systems with about 128MB of RAM.  Since
you say you have "good enough hardware", I'm assuming you have a bit
more than that.  The first things to try here are the list at
http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ; your bad
query here looks like it might benefit from a large increase to
effective_cache_size, and possibly an increase to work_mem as well.
Your "bad" plan here is doing a lot of sequential scans instead of
indexed lookups, which makes me wonder if the change in join types
you're forcing isn't fixing that part as a coincidence.

Note that the estimated number of rows coming out of each form of plan
is off by a factor of about 200X, so it's not that the other plan type
is better estimating anything.

--
Greg Smith   2ndQuadrant US    greg@2ndQuadrant.com   Baltimore, MD
PostgreSQL Training, Services, and 24x7 Support  www.2ndQuadrant.us
"PostgreSQL 9.0 High Performance": http://www.2ndQuadrant.com/books


Re: Query performance with disabled hashjoin and mergejoin

От
Ivan Voras
Дата:
On 04/02/2011 15:44, Greg Smith wrote:
> Ivan Voras wrote:
>> The "vanilla" plan, with default settings is:
>
> Pause here for a second: why default settings? A default PostgreSQL
> configuration is suitable for systems with about 128MB of RAM. Since you
> say you have "good enough hardware", I'm assuming you have a bit more
> than that. The first things to try here are the list at
> http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ; your bad
> query here looks like it might benefit from a large increase to
> effective_cache_size, and possibly an increase to work_mem as well. Your
> "bad" plan here is doing a lot of sequential scans instead of indexed
> lookups, which makes me wonder if the change in join types you're
> forcing isn't fixing that part as a coincidence.

My earlier message didn't get through so here's a repeat:

Sorry for the confusion, by "default settings" I meant "planner default
settings" not generic shared buffers, wal logs, work memory etc. - which
are adequately tuned.

> Note that the estimated number of rows coming out of each form of plan
> is off by a factor of about 200X, so it's not that the other plan type
> is better estimating anything.

Any ideas how to fix the estimates? Or will I have to simulate hints by
issuing "set enable_hashjoin=f; set enable_mergejoin=f;" for this query? :)


Re: Query performance with disabled hashjoin and mergejoin

От
Ivan Voras
Дата:
Sorry for the misunderstaning: of course not default "normal" settings; shared buffers, work mem, wal segments and others have been tuned according to available hardware (e.g. 4 GB, 32 MB, 10 for these settings, respectively). I meant "planner default settings" in the post.
--
Sent from my Android phone, please excuse my brevity.

Greg Smith <greg@2ndquadrant.com> wrote:
Ivan Voras wrote: > The "vanilla" plan, with default settings is: Pause here for a second: why default settings? A default PostgreSQL configuration is suitable for systems with about 128MB of RAM. Since you say you have "good enough hardware", I'm assuming you have a bit more than that. The first things to try here are the list at http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server ; your bad query here looks like it might benefit from a large increase to effective_cache_size, and possibly an increase to work_mem as well. Your "bad" plan here is doing a lot of sequential scans instead of indexed lookups, which makes me wonder if the change in join types you're forcing isn't fixing that part as a coincidence. Note that the estimated number of rows coming out of each form of plan is off by a factor of about 200X, so it's not that the other plan type is better estimating anything. -- Greg Smith 2ndQuadrant US greg@2ndQuadrant.com Baltimore, MD PostgreSQL Training, Services, and 24x7 Support www.2ndQuadrant.us "PostgreSQL 9.0 High Performance": http://www.2ndQuadrant.com/books

Re: Query performance with disabled hashjoin and mergejoin

От
Robert Haas
Дата:
On Fri, Feb 4, 2011 at 7:08 AM, Ivan Voras <ivoras@freebsd.org> wrote:
>                                 ->  BitmapAnd  (cost=1282.94..1282.94
> rows=1430 width=0) (actual time=5.508..5.508 rows=0 loops=1)
>                                       ->  Bitmap Index Scan on
> news_index_layout_id_state  (cost=0.00..150.14 rows=2587 width=0) (actual
> time=0.909..0.909 rows=3464 loops=1)
>                                             Index Cond: ((layout_id = 8980)
> AND (state = 2))
>                                       ->  BitmapOr (cost=1132.20..1132.20
> rows=20127 width=0) (actual time=4.136..4.136 rows=0 loops=1)
>                                             ->  Bitmap Index Scan on
> news_visible_from  (cost=0.00..1122.09 rows=19976 width=0) (actual
> time=3.367..3.367 rows=19932 loops=1)
>                                                   Index Cond: (visible_from
> IS NULL)
>                                             ->  Bitmap Index Scan on
> news_visible_to  (cost=0.00..9.40 rows=151 width=0) (actual
> time=0.766..0.766 rows=43 loops=1)
>                                                   Index Cond: (1296806570 <=
> visible_to)

I think this part of the query is the problem.  Since the planner
doesn't support cross-column statistics, it can't spot the correlation
between these different search conditions, resulting in a badly broken
selectivity estimate.

Sometimes you can work around this by adding a single column, computed
with a trigger, that contains enough information to test the whole
WHERE-clause condition using a single indexable test against the
column value.  Or sometimes you can get around it by partitioning the
data into multiple tables, say with the visible_from IS NULL rows in a
different table from the rest.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Re: Query performance with disabled hashjoin and mergejoin

От
Merlin Moncure
Дата:
On Tue, Feb 22, 2011 at 9:07 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Fri, Feb 4, 2011 at 7:08 AM, Ivan Voras <ivoras@freebsd.org> wrote:
>>                                 ->  BitmapAnd  (cost=1282.94..1282.94
>> rows=1430 width=0) (actual time=5.508..5.508 rows=0 loops=1)
>>                                       ->  Bitmap Index Scan on
>> news_index_layout_id_state  (cost=0.00..150.14 rows=2587 width=0) (actual
>> time=0.909..0.909 rows=3464 loops=1)
>>                                             Index Cond: ((layout_id = 8980)
>> AND (state = 2))
>>                                       ->  BitmapOr (cost=1132.20..1132.20
>> rows=20127 width=0) (actual time=4.136..4.136 rows=0 loops=1)
>>                                             ->  Bitmap Index Scan on
>> news_visible_from  (cost=0.00..1122.09 rows=19976 width=0) (actual
>> time=3.367..3.367 rows=19932 loops=1)
>>                                                   Index Cond: (visible_from
>> IS NULL)
>>                                             ->  Bitmap Index Scan on
>> news_visible_to  (cost=0.00..9.40 rows=151 width=0) (actual
>> time=0.766..0.766 rows=43 loops=1)
>>                                                   Index Cond: (1296806570 <=
>> visible_to)
>
> I think this part of the query is the problem.  Since the planner
> doesn't support cross-column statistics, it can't spot the correlation
> between these different search conditions, resulting in a badly broken
> selectivity estimate.
>
> Sometimes you can work around this by adding a single column, computed
> with a trigger, that contains enough information to test the whole
> WHERE-clause condition using a single indexable test against the
> column value.  Or sometimes you can get around it by partitioning the
> data into multiple tables, say with the visible_from IS NULL rows in a
> different table from the rest.

Why should you need cross column statistics for this case?  You should
be able to multiple selectivity from left to right as long as you are
doing equality comparisons, yes?

Right now the planner is treating
select * from foo where (a,b,c) between (1,1,1) and (9,9,9) the same
(using selectivity on a) as
select * from foo where (a,b,c) between (1,1,5) and (1,1,7)

but they are not the same. since in the second query terms a,b are
equal, shouldn't you able to multiply the selectivity through?

merlin

Re: Query performance with disabled hashjoin and mergejoin

От
Robert Haas
Дата:
On Mon, Mar 7, 2011 at 3:40 PM, Merlin Moncure <mmoncure@gmail.com> wrote:
> On Tue, Feb 22, 2011 at 9:07 PM, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Fri, Feb 4, 2011 at 7:08 AM, Ivan Voras <ivoras@freebsd.org> wrote:
>>>                                 ->  BitmapAnd  (cost=1282.94..1282.94
>>> rows=1430 width=0) (actual time=5.508..5.508 rows=0 loops=1)
>>>                                       ->  Bitmap Index Scan on
>>> news_index_layout_id_state  (cost=0.00..150.14 rows=2587 width=0) (actual
>>> time=0.909..0.909 rows=3464 loops=1)
>>>                                             Index Cond: ((layout_id = 8980)
>>> AND (state = 2))
>>>                                       ->  BitmapOr (cost=1132.20..1132.20
>>> rows=20127 width=0) (actual time=4.136..4.136 rows=0 loops=1)
>>>                                             ->  Bitmap Index Scan on
>>> news_visible_from  (cost=0.00..1122.09 rows=19976 width=0) (actual
>>> time=3.367..3.367 rows=19932 loops=1)
>>>                                                   Index Cond: (visible_from
>>> IS NULL)
>>>                                             ->  Bitmap Index Scan on
>>> news_visible_to  (cost=0.00..9.40 rows=151 width=0) (actual
>>> time=0.766..0.766 rows=43 loops=1)
>>>                                                   Index Cond: (1296806570 <=
>>> visible_to)
>>
>> I think this part of the query is the problem.  Since the planner
>> doesn't support cross-column statistics, it can't spot the correlation
>> between these different search conditions, resulting in a badly broken
>> selectivity estimate.
>>
>> Sometimes you can work around this by adding a single column, computed
>> with a trigger, that contains enough information to test the whole
>> WHERE-clause condition using a single indexable test against the
>> column value.  Or sometimes you can get around it by partitioning the
>> data into multiple tables, say with the visible_from IS NULL rows in a
>> different table from the rest.
>
> Why should you need cross column statistics for this case?  You should
> be able to multiple selectivity from left to right as long as you are
> doing equality comparisons, yes?
>
> Right now the planner is treating
> select * from foo where (a,b,c) between (1,1,1) and (9,9,9) the same
> (using selectivity on a) as
> select * from foo where (a,b,c) between (1,1,5) and (1,1,7)
>
> but they are not the same. since in the second query terms a,b are
> equal, shouldn't you able to multiply the selectivity through?

I'm not quite following that...

The reason I thought cross-column correlations might be relevant is
that the bitmap index scan on news_visible_from is quite accurate
(19976 estimated vs. 19932 actual) and the bitmap index scan on
news_visible_to is tolerably accurate (151 estimated vs. 41 actual)
but the estimate on the BitmapOr is somehow totally wrong (20127
estimated vs. 0 actual).  But on further reflection that doesn't make
much sense.  How can the BitmapOr produce fewer rows than the sum of
its constituent inputs?

/me scratches head.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Re: Query performance with disabled hashjoin and mergejoin

От
Tom Lane
Дата:
Robert Haas <robertmhaas@gmail.com> writes:
> The reason I thought cross-column correlations might be relevant is
> that the bitmap index scan on news_visible_from is quite accurate
> (19976 estimated vs. 19932 actual) and the bitmap index scan on
> news_visible_to is tolerably accurate (151 estimated vs. 41 actual)
> but the estimate on the BitmapOr is somehow totally wrong (20127
> estimated vs. 0 actual).  But on further reflection that doesn't make
> much sense.  How can the BitmapOr produce fewer rows than the sum of
> its constituent inputs?

That's not an estimation bug, that's a measurement bug.  We don't try to
count the actual number of rows present in the result of a BitmapOr or
BitmapAnd node.  (It would be impractical in lossy cases anyway, not to
mention expensive.)

            regards, tom lane

Re: Query performance with disabled hashjoin and mergejoin

От
Merlin Moncure
Дата:
On Tue, Mar 8, 2011 at 2:57 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Mon, Mar 7, 2011 at 3:40 PM, Merlin Moncure <mmoncure@gmail.com> wrote:
>> On Tue, Feb 22, 2011 at 9:07 PM, Robert Haas <robertmhaas@gmail.com> wrote:
>>> On Fri, Feb 4, 2011 at 7:08 AM, Ivan Voras <ivoras@freebsd.org> wrote:
>>>>                                 ->  BitmapAnd  (cost=1282.94..1282.94
>>>> rows=1430 width=0) (actual time=5.508..5.508 rows=0 loops=1)
>>>>                                       ->  Bitmap Index Scan on
>>>> news_index_layout_id_state  (cost=0.00..150.14 rows=2587 width=0) (actual
>>>> time=0.909..0.909 rows=3464 loops=1)
>>>>                                             Index Cond: ((layout_id = 8980)
>>>> AND (state = 2))
>>>>                                       ->  BitmapOr (cost=1132.20..1132.20
>>>> rows=20127 width=0) (actual time=4.136..4.136 rows=0 loops=1)
>>>>                                             ->  Bitmap Index Scan on
>>>> news_visible_from  (cost=0.00..1122.09 rows=19976 width=0) (actual
>>>> time=3.367..3.367 rows=19932 loops=1)
>>>>                                                   Index Cond: (visible_from
>>>> IS NULL)
>>>>                                             ->  Bitmap Index Scan on
>>>> news_visible_to  (cost=0.00..9.40 rows=151 width=0) (actual
>>>> time=0.766..0.766 rows=43 loops=1)
>>>>                                                   Index Cond: (1296806570 <=
>>>> visible_to)
>>>
>>> I think this part of the query is the problem.  Since the planner
>>> doesn't support cross-column statistics, it can't spot the correlation
>>> between these different search conditions, resulting in a badly broken
>>> selectivity estimate.
>>>
>>> Sometimes you can work around this by adding a single column, computed
>>> with a trigger, that contains enough information to test the whole
>>> WHERE-clause condition using a single indexable test against the
>>> column value.  Or sometimes you can get around it by partitioning the
>>> data into multiple tables, say with the visible_from IS NULL rows in a
>>> different table from the rest.
>>
>> Why should you need cross column statistics for this case?  You should
>> be able to multiple selectivity from left to right as long as you are
>> doing equality comparisons, yes?
>>
>> Right now the planner is treating
>> select * from foo where (a,b,c) between (1,1,1) and (9,9,9) the same
>> (using selectivity on a) as
>> select * from foo where (a,b,c) between (1,1,5) and (1,1,7)
>>
>> but they are not the same. since in the second query terms a,b are
>> equal, shouldn't you able to multiply the selectivity through?
>
> I'm not quite following that...
>
> The reason I thought cross-column correlations might be relevant is
> that the bitmap index scan on news_visible_from is quite accurate
> (19976 estimated vs. 19932 actual) and the bitmap index scan on
> news_visible_to is tolerably accurate (151 estimated vs. 41 actual)
> but the estimate on the BitmapOr is somehow totally wrong (20127
> estimated vs. 0 actual).  But on further reflection that doesn't make
> much sense.  How can the BitmapOr produce fewer rows than the sum of
> its constituent inputs?
>
> /me scratches head.

my fault -- the point i was making I think was valid but didn't apply
to the op's question: I mistakenly where expression could be converted
to row wise comparison type operation but that wasn't the case...

merlin

Re: Query performance with disabled hashjoin and mergejoin

От
Robert Haas
Дата:
On Tue, Mar 8, 2011 at 4:24 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Robert Haas <robertmhaas@gmail.com> writes:
>> The reason I thought cross-column correlations might be relevant is
>> that the bitmap index scan on news_visible_from is quite accurate
>> (19976 estimated vs. 19932 actual) and the bitmap index scan on
>> news_visible_to is tolerably accurate (151 estimated vs. 41 actual)
>> but the estimate on the BitmapOr is somehow totally wrong (20127
>> estimated vs. 0 actual).  But on further reflection that doesn't make
>> much sense.  How can the BitmapOr produce fewer rows than the sum of
>> its constituent inputs?
>
> That's not an estimation bug, that's a measurement bug.  We don't try to
> count the actual number of rows present in the result of a BitmapOr or
> BitmapAnd node.  (It would be impractical in lossy cases anyway, not to
> mention expensive.)

Mmm, OK.  But I still think there's a problem with the selectivity
estimate in there somewhere, because

                          ->  Bitmap Heap Scan on news
(cost=1282.94..5494.05 rows=1422 width=634) (actual time=5.532..5.560
rows=7 loops=1)

...which may be why the planner is going wrong for the OP.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company