Fix estimates for ModifyTable paths without RETURNING.
authorThomas Munro <tmunro@postgresql.org>
Mon, 12 Oct 2020 07:41:16 +0000 (20:41 +1300)
committerThomas Munro <tmunro@postgresql.org>
Mon, 12 Oct 2020 11:26:49 +0000 (00:26 +1300)
In the past, we always estimated that a ModifyTable node would emit the
same number of rows as its subpaths.  Without a RETURNING clause, the
correct estimate is zero.  Fix, in preparation for a proposed parallel
write patch that is sensitive to that number.

A remaining problem is that for RETURNING queries, the estimated width
is based on subpath output rather than the RETURNING tlist.

Reviewed-by: Greg Nancarrow <gregn4422@gmail.com>
Discussion: https://postgr.es/m/CAJcOf-cXnB5cnMKqWEp2E2z7Mvcd04iLVmV%3DqpFJrR3AcrTS3g%40mail.gmail.com

src/backend/optimizer/util/pathnode.c

index c1fc866cbf911049639c83be78b560bdc9b5a8fc..5281a2f9983ffcd7c6706a1f3778c1f41bdd034b 100644 (file)
@@ -3583,15 +3583,18 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
                if (lc == list_head(subpaths))  /* first node? */
                        pathnode->path.startup_cost = subpath->startup_cost;
                pathnode->path.total_cost += subpath->total_cost;
-               pathnode->path.rows += subpath->rows;
-               total_size += subpath->pathtarget->width * subpath->rows;
+               if (returningLists != NIL)
+               {
+                       pathnode->path.rows += subpath->rows;
+                       total_size += subpath->pathtarget->width * subpath->rows;
+               }
        }
 
        /*
         * Set width to the average width of the subpath outputs.  XXX this is
-        * totally wrong: we should report zero if no RETURNING, else an average
-        * of the RETURNING tlist widths.  But it's what happened historically,
-        * and improving it is a task for another day.
+        * totally wrong: we should return an average of the RETURNING tlist
+        * widths.  But it's what happened historically, and improving it is a task
+        * for another day.
         */
        if (pathnode->path.rows > 0)
                total_size /= pathnode->path.rows;