Re: plan variations: join vs. exists vs. row comparison

Поиск
Список
Период
Сортировка
От Merlin Moncure
Тема Re: plan variations: join vs. exists vs. row comparison
Дата
Msg-id AANLkTikGCt1pkDW60zA8sGWPJoLd3ktCEejHCiqM65xK@mail.gmail.com
обсуждение исходный текст
Ответ на plan variations: join vs. exists vs. row comparison  (Jon Nelson <jnelson+pgsql@jamponi.net>)
Список pgsql-performance
On Mon, Mar 7, 2011 at 1:07 PM, Jon Nelson <jnelson+pgsql@jamponi.net> wrote:
> Originally, I posted to -general but I found some time to write some
> samples, and realized it's probably more of a performance question.
>
> The original post is here:
> http://archives.postgresql.org/pgsql-general/2011-03/msg00198.php
>
> I was hoping that somebody could help me understand the differences
> between three plans.
> All of the plans are updating a table using a second table, and should
> be logically equivalent.
> Two of the plans use joins, and one uses an exists subquery.
> One of the plans uses row constructors and IS NOT DISTINCT FROM. It is
> this plan which has really awful performance.

The problem is really coming from SQL: it requires row wise
comparisons to be of all fields in left to right order and the fact
that you can't match NULL to NULL with =.

If you have a table with a,b,c, (1,1,NULL) is not distinct from (1,2,3) becomes:
Filter: ((NOT (a IS DISTINCT FROM 1)) AND (NOT (b IS DISTINCT FROM 1))
AND (NOT (c IS DISTINCT FROM NULL::integer)))

At present postgresql does not have the facilities to turn that into
an index lookup.  SQL doesn't allow the way you'd want to write this
the way you'd really like to:

select * from v where (a,b,c) = (1,1,NULL);

because the comparison can't be applied from a row to another row but
only between the member fields. You can cheat the system, but only if
you reserve a special index for that purpose:

create table v(a int, b int, c int);
create index on v(v);
select * from v where v = (1,1, NULL) will match as 'is not distinct
from' does, using the index.  This is because composite type
comparison (as opposed to its fields) follows a different code path.
Confused yet?  You can also use the above trick with a type if you are
not comparing all fields of 'v':

create type foo(a int, b int);
create index on v(((a,b)::foo));
select * from v where (a,b)::foo = (1,1);

will get you field subset comparison with index.  Note if you do the
above, the index can only match on the entire composite, not
particular fields...

merlin

В списке pgsql-performance по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: plan variations: join vs. exists vs. row comparison
Следующее
От: Jon Nelson
Дата:
Сообщение: Re: plan variations: join vs. exists vs. row comparison