Re: default range partition and constraint exclusion

From: Amit Langote <Langote_Amit_f8(at)lab(dot)ntt(dot)co(dot)jp>
To: Kyotaro HORIGUCHI <horiguchi(dot)kyotaro(at)lab(dot)ntt(dot)co(dot)jp>, robertmhaas(at)gmail(dot)com
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: default range partition and constraint exclusion
Date: 2017-11-28 11:44:47
Message-ID: 72dc9717-6ba2-dc41-ee92-462248977321@lab.ntt.co.jp
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Horiguchi-san, thanks for the clarifying comment.

On 2017/11/27 18:04, Kyotaro HORIGUCHI wrote:
> At Fri, 24 Nov 2017 10:49:07 -0500, Robert Haas wrote
>> OK, so I am still confused about whether the constraint is wrong or
>> the constraint exclusion logic is wrong. One of them, at least, has
>> to be wrong, and we have to fix whichever one is wrong. Fixing broken
>> constraint exclusion logic by hacking up the constraint, or conversely
>> fixing a broken constraint by hacking up the constraint exclusion
>> logic, wouldn't be right.
>>
>> I think my last email was confused: I thought that the (2, null) tuple
>> was ending up in mc2p2, but it's really ending up in mc2p_default,
>> whose constraint currently looks like this:
>>
>> NOT (
>> ((a < 1) OR ((a = 1) AND (b < 1)))
>> OR
>> ((a > 1) OR ((a = 1) AND (b >= 1)))
>> )
>>
>> Now where exactly is constraint exclusion going wrong here? a = 2
>> refutes a < 1 and a = 1, which means that (a < 1) OR ((a = 1) AND (b <
>> 1)) must be false and that (a = 1) AND (b >= 1) must also be false.
>> But (a > 1) could be either true or null, which means (a > 1) OR ((a =
>
> a > 1 is true when a = 2, so the second term is true?

Yes.

>> 1) AND (b >= 1)) can be true or null, which means the whole thing can
>> be false or null, which means that it is not refuted by a = 2. It
>
> Then the whole thing is false.

Yes, too.

>> should be possible to dig down in there step by step and figure out
>> where the wheels are coming off -- have you tried to do that?
>
> | select NOT (
> | ((a < 1) OR ((a = 1) AND (b < 1)))
> | OR
> | ((a > 1) OR ((a = 1) AND (b >= 1)))
> | )
> | from (values (2::int, null::int)) as t(a, b);
> | ?column?
> | ----------
> | f
>
> The problem here I think is that get_qual_for_range() for default
> partition returns an inconsistent qual with what partition
> get_partition_for_tuple chooses for keys containing nulls. It
> chooses default partition if any of the key values is null,
> without referring the constraint expression.

Right.

> The current behavior is apparently odd.
>
> | select pg_get_partition_constraintdef('mc2p2'::regclass);
> | pg_get_partition_constraintdef
> | ----------------------------------------------------------------------------
> | ((a IS NOT NULL) AND (b IS NOT NULL) AND ((a > 1) OR ((a = 1) AND (b >= 1))))
>
>
> | select pg_get_partition_constraintdef('mc2p_default'::regclass);
> | pg_get_partition_constraintdef
> |
> | ---------------------------------------------------------------------------
> | (NOT (((a < 1) OR ((a = 1) AND (b < 1))) OR ((a > 1) OR ((a = 1) AND (b >= 1)))))
>
>
> | insert into mc2p2 values (2);
> | ERROR: new row for relation "mc2p2" violates partition constraint
> | DETAIL: Failing row contains (2, null).
>
> This is the correct behavior.

Yes, a non-default range partition does not accept nulls in any of the
partition keys.

> | insert into mc2p_default values (2);
> | ERROR: new row for relation "mc2p_default" violates partition constraint
> | DETAIL: Failing row contains (2, null).
>
> This is the correct behavior in terms of constraint, but
> incorrect in terms of partition routing.
>
> But interestingly, the following *works*, in a way contradicting
> to the constraint.
>
> | insert into mc2p values (2);
> | INSERT 0 1
> |
> | select * from mc2p_default;
> | a | b
> | ---+---
> | 2 |
> | (1 row)

That is, the default partition's constraint, as currently generated, is wrong.

> After applying the patch upthread, get_qual_for_range() returns
> the consistent qual and "insert into mc2p_default values (2)" is
> accepted correctly and everything become consistent.

Thanks for testing.

Thanks,
Amit

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Jan Michálek 2017-11-28 12:20:51 Re: [HACKERS] Other formats in pset like markdown, rst, mediawiki
Previous Message Kyotaro HORIGUCHI 2017-11-28 11:39:15 Re: [HACKERS] path toward faster partition pruning