Re: [HACKERS] Asymmetry between parent and child wrt "false" quals - Mailing list pgsql-hackers
From | Amit Langote |
---|---|
Subject | Re: [HACKERS] Asymmetry between parent and child wrt "false" quals |
Date | |
Msg-id | e35e13cf-87bc-58e6-848d-a74be66f8b8f@lab.ntt.co.jp Whole thread Raw |
In response to | [HACKERS] Asymmetry between parent and child wrt "false" quals (Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>) |
Responses |
Re: [HACKERS] Asymmetry between parent and child wrt "false" quals
|
List | pgsql-hackers |
On 2017/03/21 14:59, Ashutosh Bapat wrote: > When I run a query like below on a child-less table, the plan comes out to be > > explain verbose SELECT * FROM uprt1_l WHERE a = 1 AND a = 2; > QUERY PLAN > ---------------------------------------------------------------------- > Result (cost=0.00..11.50 rows=1 width=13) > Output: a, b, c > One-Time Filter: false > -> Seq Scan on public.uprt1_l (cost=0.00..11.50 rows=1 width=13) > Output: a, b, c > Filter: (uprt1_l.a = 1) > (6 rows) > > where as the same query run on a parent with children, the plan is > postgres=# \d prt1_l > Table "public.prt1_l" > Column | Type | Collation | Nullable | Default > --------+-------------------+-----------+----------+--------- > a | integer | | not null | > b | integer | | | > c | character varying | | | > Partition key: RANGE (a) > Number of partitions: 3 (Use \d+ to list them.) > > postgres=# explain verbose SELECT * FROM prt1_l WHERE a = 1 AND a = 2; > QUERY PLAN > ------------------------------------------- > Result (cost=0.00..0.00 rows=0 width=40) > Output: prt1_l.a, prt1_l.b, prt1_l.c > One-Time Filter: false > (3 rows) > > For a parent table with children, set_append_rel_size() evaluates > restrictions in loop > 880 foreach(l, root->append_rel_list) > 881 { > 882 AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); > > starting at 1021. If any of the restrictions are evaluated to false, > it set the child as dummy. If all children are dummy, the appendrel is > set to dummy. > > But for a child-less table, even if the "false" qual is available in > baserestrictinfo in set_rel_size(), we do not mark the relation as > dummy. Instead, paths are created for it and only at the time of > planning we add the gating plan when there is a pseudo constant quals. > Why do we have different behaviours in these two cases? I think the case where there is no child table would not be handled by set_append_rel_size(), because rte->inh would be false. Instead, I thought the test at the beginning of relation_excluded_by_constraints() would have detected this somehow; the comment there says the following: /** Regardless of the setting of constraint_exclusion, detect* constant-FALSE-or-NULL restriction clauses. Because const-foldingwill* reduce "anything AND FALSE" to just "FALSE", any such case should* result in exactly one baserestrictinfoentry. But the qual (a = 1 and a = 2) is *not* reduced to exactly one constant-false-or-null baserestrictinfo entry; instead I see that there are two RestrictInfos viz. a = 1 and const-FALSE at that point. I think the const-folding mentioned in the above comment does not occur after equivalence class processing, which would be required to conclude that (a = 1 and a = 2) reduces to constant-false. OTOH, (a = 1 and false) can be reduced to constant-false much earlier when performing preprocess_qual_conditions(). That said, I am not sure if it's worthwhile to modify the test at the beginning of relation_excluded_by_constraints() to iterate over rel->baserestrictinfos to look for any const-FALSE quals, instead of doing it only when there *only* the const-FALSE qual. Thanks, Amit
pgsql-hackers by date: