Re: HashJoin order, hash the large or small table? Postgres likes to hash the big one, why?

From: Scott Carey <scott(at)richrelevance(dot)com>
To: Scott Carey <scott(at)richrelevance(dot)com>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Robert Haas <robertmhaas(at)gmail(dot)com>, "pgsql-performance(at)postgresql(dot)org Performance" <pgsql-performance(at)postgresql(dot)org>
Subject: Re: HashJoin order, hash the large or small table? Postgres likes to hash the big one, why?
Date: 2011-04-13 17:22:40
Message-ID: C9CB28BE.306C0%scott@richrelevance.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-performance

New email-client nightmares! Fixed below. I think.
-------------

Sorry for resurrecting this thread, but this has been in my outbox for
months and I think it is important:

>On Oct 27, 2010, at 12:56 PM, Tom Lane wrote:
>
>
>> Scott Carey writes:
>>Why does hashjoin behave poorly when the inner relation is not
>
>>uniformly distributed and the outer is?
>
>
>
> Because a poorly distributed inner relation leads to long hash chains.
> In the very worst case, all the keys are on the same hash chain and it
> degenerates to a nested-loop join. (There is an assumption in the
> costing code that the longer hash chains also tend to get searched more
> often, which maybe doesn't apply if the outer rel is flat, but it's not
> obvious that it's safe to not assume that.)
>

I disagree. Either
1: The estimator is wrong
or
2: The hash data structure is flawed.

A pathological skew case (all relations with the same key), should be
_cheaper_ to probe. There should be only _one_ entry in the hash (for
the one key), and that entry will be a list of all relations matching the
key. Therefore, hash probes will either instantly fail to match on an
empty bucket, fail to match the one key with one compare, or match the one
key and join on the matching list.

In particular for anti-join, high skew should be the best case scenario.

A hash structure that allows multiple entries per key is inappropriate for
skewed data, because it is not O(n). One that has one entry per key
remains O(n) for all skew. Furthermore, the hash buckets and # of entries
is proportional to n_distinct in this case, and smaller and more cache and
memory friendly to probe.

>Not really. It's still searching a long hash chain; maybe it will find
> an exact match early in the chain, or maybe not. It's certainly not
> *better* than antijoin with a well-distributed inner rel.

There shouldn't be long hash chains. A good hash function + proper bucket
count + one entry per key = no long chains.

> Although the
> point is moot, anyway, since if it's an antijoin there is only one
> candidate for which rel to put on the outside.

You can put either relation on the outside with an anti-join, but would
need a different algorithm and cost estimator if done the other way
around. Construct a hash on the join key, that keeps a list of relations
per key, iterate over the other relation, and remove the key and
corresponding list from the hash when there is a match, when complete the
remaining items in the hash are the result of the join (also already
grouped by the key). It could be terminated early if all entries are
removed.
This would be useful if the hash was small, the other side of the hash too
large to fit in memory, and alternative was a massive sort on the other
relation.

Does the hash cost estimator bias towards smaller hashes due to hash probe
cost increasing with hash size due to processor caching effects? Its not
quite O(n) due to caching effects.

>
>> regards, tom lane

In response to

Responses

Browse pgsql-performance by date

  From Date Subject
Next Message Tom Lane 2011-04-13 17:35:31 Re: HashJoin order, hash the large or small table? Postgres likes to hash the big one, why?
Previous Message Scott Carey 2011-04-13 17:07:53 Re: HashJoin order, hash the large or small table? Postgres likes to hash the big one, why?