On Mon, Jul 10, 2017 at 2:59 PM, Kyotaro HORIGUCHI
<horiguchi.kyot...@lab.ntt.co.jp> wrote:
> Hello,

Thanks for the review.

>> If a partitioned table is proven dummy, set_rel_pathlist() doesn't mark the
>> partition relations dummy and thus doesn't set any (dummy) paths in the
>> partition relations. The lack of paths in the partitions means that we can
>
> A parent won't be proven dummy directly but be a dummy rel (means
> IS_DUMMY_REL(rel) returns true) if no child is attached as the
> result of constarint exlusion.

In a query like SELECT * FROM parent WHERE 1 = 2; the parent is marked
dummy in set_rel_size()
 319 set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 320              Index rti, RangeTblEntry *rte)
 321 {
 322     if (rel->reloptkind == RELOPT_BASEREL &&
 323         relation_excluded_by_constraints(root, rel, rte))
 324     {
 325         /*
 326          * We proved we don't need to scan the rel via constraint
exclusion,
 327          * so set up a single dummy path for it.  Here we only
check this for
 328          * regular baserels; if it's an otherrel, CE was already checked in
 329          * set_append_rel_size().
 330          *
 331          * In this case, we go ahead and set up the relation's
path right away
 332          * instead of leaving it for set_rel_pathlist to do.
This is because
 333          * we don't have a convention for marking a rel as dummy except by
 334          * assigning a dummy path to it.
 335          */
 336         set_dummy_rel_pathlist(rel);
 337     }

It's in such cases, that a parent is proven dummy without looking at
the child relations.

>
>> not use partition-wise join while joining this table with some other 
>> similarly
>> partitioned table as the partitions do not have any paths that child-joins 
>> can
>> use. This means that we can not create partition relations for such a join 
>> and
>> thus can not consider the join to be partitioned. This doesn't matter much 
>> when
>> the dummy relation is the outer relation, since the resultant join is also
>> dummy. But when the dummy relation is inner relation, the resultant join is 
>> not
>> dummy and can be considered to be partitioned with same partitioning scheme 
>> as
>> the outer relation to be joined with other similarly partitioned table. Not
>> having paths in the partitions deprives us of this future optimization.
>> Without partition-wise join, not setting dummy paths in the partition 
>> relations
>> makes sense, since those do not have any use. But with partition-wise join 
>> that
>> changes.
>
> Of course for inner-joins and even for outer-joins, there's no
> point in considering the children of a dummy parent as a side of
> a join. For what reason, or in what case does partition-wise join
> need to consider children of a proven-dummy parent?

Consider a join A LEFT JOIN B LEFT JOIN C where B is proven dummy and
A, B and C are all partitioned with the same partitioning scheme. The
result of A LEFT JOIN B is same as appending Ak LEFT JOIN Bk where Ak
and Bk are matching partitions of A and B resp. When we join this with
C, the result would be same as appending Ak LEFT JOIN Bk LEFT JOIN Ck
where Ck is partition matching Ak and Bk. So, even though B is proven
dummy, we can execute A LEFT JOIN B LEFT JOIN C as a partition-wise
join, if we can execute A LEFT JOIN B as a partition-wise join.

Does that answer your question?

>
>> If we always mark the partitions dummy, that effort may get wasted if the
>> partitioned table doesn't participate in the partition-wise join. A possible
>> solution would be to set the partitions dummy when only the partitioned table
>> participates in the join, but that happens during make_join_rel(), much after
>> we have set up the simple relations. So, I am not sure, whether that's a good
>> option. But I am open to suggestions.
>>
>> What if we always mark the partition relations of a dummy partitioned table
>> dummy? I tried attached path on a thousand partition table, the planning time
>> increased by 3-5%. That doesn't look that bad for a thousand partitions.
>>
>> Any other options/comments?
>
> Since I don't understand the meaning of the patch, the comments
> below are just from a micro-viewpoint.
>
> -       if (IS_DUMMY_REL(rel))
> +       if (IS_DUMMY_REL(rel) && !rte->inh)
>
> In set_rel_pathlist, if want to exlude the inh==true case from
> the first if, just inverting the first and second if caluses
> would be enough, like this.
>
> |  if (rte->inh)
> |    set_append_rel_pathlist(root, rel, rti, rte);
> |  else if (IS_DUMMY_REL(rel))
> |    /* We already proved the relation empty, so nothing more to do *

Right. Done in the attached patch.

>
> +               if (IS_DUMMY_REL(rel))
> +                       set_dummy_rel_pathlist(childrel);
>
> This is equivalent of just returning before looking over
> append_rel_list when rel is a dummy. It doesn't seem to me to add
> marked-as-dummy children to a dummy parent. (I understand that is
> the objective of this patch.)

Not really. It sets the dummy path list in child, which won't be done
if we return without traversing append_rel_list, esp. when the parent
is marked dummy without marking any of its children dummy as explained
above.

But we could avoid marking a child dummy twice, in case the parent was
marked dummy because all of its children were marked dummy.  I have
fixed this case in the attached patch.


-- 
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index f087ddb..f5c5a4f 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -421,14 +421,17 @@ static void
 set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 				 Index rti, RangeTblEntry *rte)
 {
-	if (IS_DUMMY_REL(rel))
+	if (rte->inh)
 	{
-		/* We already proved the relation empty, so nothing more to do */
+		/*
+		 * It's an "append relation", process accordingly. If the "append
+		 * relation" is dummy, mark its children dummy, if not done so already.
+		 */
+		set_append_rel_pathlist(root, rel, rti, rte);
 	}
-	else if (rte->inh)
+	else if (IS_DUMMY_REL(rel))
 	{
-		/* It's an "append relation", process accordingly */
-		set_append_rel_pathlist(root, rel, rti, rte);
+		/* We already proved the relation empty, so nothing more to do */
 	}
 	else
 	{
@@ -1242,8 +1245,11 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 			childrel->consider_parallel = false;
 
 		/*
-		 * Compute the child's access paths.
+		 * Compute the child's access paths. A child is empty if its parent is
+		 * proven dummy.
 		 */
+		if (IS_DUMMY_REL(rel) && !IS_DUMMY_REL(childrel))
+			set_dummy_rel_pathlist(childrel);
 		set_rel_pathlist(root, childrel, childRTindex, childRTE);
 
 		/*
@@ -1258,6 +1264,12 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		live_childrels = lappend(live_childrels, childrel);
 	}
 
+	if (!live_childrels)
+	{
+		Assert(IS_DUMMY_REL(rel));
+		return;
+	}
+
 	/* Add paths to the "append" relation. */
 	add_paths_to_append_rel(root, rel, live_childrels);
 }
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to