Re: Optimizing nested ConvertRowtypeExpr execution

Поиск
Список
Период
Сортировка
От Andrew Gierth
Тема Re: Optimizing nested ConvertRowtypeExpr execution
Дата
Msg-id 87zhum1dmx.fsf@news-spur.riddles.org.uk
обсуждение исходный текст
Ответ на Re: Optimizing nested ConvertRowtypeExpr execution  (Andrew Gierth <andrew@tao11.riddles.org.uk>)
Ответы Re: Optimizing nested ConvertRowtypeExpr execution  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
>>>>> "Andrew" == Andrew Gierth <andrew@tao11.riddles.org.uk> writes:

 Andrew> I'm going to pull all this together and commit it shortly.

Here's the patch with my edits (more comments and the while/if change).

I'll commit this in due course unless I hear otherwise.

-- 
Andrew (irc:RhodiumToad)

From 9cc81cea6de41140fe361bff375190bfdd188ae9 Mon Sep 17 00:00:00 2001
From: Andrew Gierth <rhodiumtoad@postgresql.org>
Date: Tue, 6 Nov 2018 14:19:40 +0000
Subject: [PATCH] Optimize nested ConvertRowtypeExpr nodes.

A ConvertRowtypeExpr is used to translate a whole-row reference of a
child to that of a parent. The planner produces nested
ConvertRowtypeExpr while translating whole-row reference of a leaf
partition in a multi-level partition hierarchy. Executor then
translates the whole-row reference from the leaf partition into all
the intermediate parent's whole-row references before arriving at the
final whole-row reference. It could instead translate the whole-row
reference from the leaf partition directly to the top-most parent's
whole-row reference skipping any intermediate translations.

Ashutosh Bapat, with tests by Kyotaro Horiguchi and some
editorialization by me. Reviewed by Andres Freund, Pavel Stehule,
Kyotaro Horiguchi, Dmitry Dolgov.
---
 src/backend/optimizer/util/clauses.c  | 46 +++++++++++++++++++++++++++++++++++
 src/test/regress/expected/inherit.out | 18 ++++++++++++++
 src/test/regress/sql/inherit.sql      |  5 ++++
 3 files changed, 69 insertions(+)

diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 21bf5dea9c..d13c3ac895 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -3716,6 +3716,52 @@ eval_const_expressions_mutator(Node *node,
                                                       context);
             }
             break;
+        case T_ConvertRowtypeExpr:
+            {
+                ConvertRowtypeExpr *cre = castNode(ConvertRowtypeExpr, node);
+                Node           *arg;
+                ConvertRowtypeExpr *newcre;
+
+                arg = eval_const_expressions_mutator((Node *) cre->arg,
+                                                     context);
+
+                newcre = makeNode(ConvertRowtypeExpr);
+                newcre->resulttype = cre->resulttype;
+                newcre->convertformat = cre->convertformat;
+                newcre->location = cre->location;
+
+                /*
+                 * In case of a nested ConvertRowtypeExpr, we can convert the
+                 * leaf row directly to the topmost row format without any
+                 * intermediate conversions. (This works because
+                 * ConvertRowtypeExpr is used only for child->parent
+                 * conversion in inheritance trees, which works by exact match
+                 * of column name, and a column absent in an intermediate
+                 * result can't be present in the final result.)
+                 *
+                 * No need to check more than one level deep, because the
+                 * above recursion will have flattened anything else.
+                 */
+                if (arg != NULL && IsA(arg, ConvertRowtypeExpr))
+                {
+                    ConvertRowtypeExpr *argcre = castNode(ConvertRowtypeExpr, arg);
+
+                    arg = (Node *) argcre->arg;
+
+                    /*
+                     * Make sure an outer implicit conversion can't hide an
+                     * inner explicit one.
+                     */
+                    if (newcre->convertformat == COERCE_IMPLICIT_CAST)
+                        newcre->convertformat = argcre->convertformat;
+                }
+
+                newcre->arg = (Expr *) arg;
+
+                if (arg != NULL && IsA(arg, Const))
+                    return ece_evaluate_expr((Node *) newcre);
+                return (Node *) newcre;
+            }
         default:
             break;
     }
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index d768e5df2c..1e00c849f3 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -764,6 +764,8 @@ NOTICE:  drop cascades to table c1
 -- tables. See the pgsql-hackers thread beginning Dec. 4/04
 create table base (i integer);
 create table derived () inherits (base);
+create table more_derived (like derived, b int) inherits (derived);
+NOTICE:  merging column "i" with inherited definition
 insert into derived (i) values (0);
 select derived::base from derived;
  derived 
@@ -777,6 +779,22 @@ select NULL::derived::base;
  
 (1 row)
 
+-- remove redundant conversions.
+explain (verbose on, costs off) select row(i, b)::more_derived::derived::base from more_derived;
+                QUERY PLAN                 
+-------------------------------------------
+ Seq Scan on public.more_derived
+   Output: (ROW(i, b)::more_derived)::base
+(2 rows)
+
+explain (verbose on, costs off) select (1, 2)::more_derived::derived::base;
+      QUERY PLAN       
+-----------------------
+ Result
+   Output: '(1)'::base
+(2 rows)
+
+drop table more_derived;
 drop table derived;
 drop table base;
 create table p1(ff1 int);
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index e8b6448f3c..afc72f47bc 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -237,9 +237,14 @@ drop table p1 cascade;
 -- tables. See the pgsql-hackers thread beginning Dec. 4/04
 create table base (i integer);
 create table derived () inherits (base);
+create table more_derived (like derived, b int) inherits (derived);
 insert into derived (i) values (0);
 select derived::base from derived;
 select NULL::derived::base;
+-- remove redundant conversions.
+explain (verbose on, costs off) select row(i, b)::more_derived::derived::base from more_derived;
+explain (verbose on, costs off) select (1, 2)::more_derived::derived::base;
+drop table more_derived;
 drop table derived;
 drop table base;
 
-- 
2.11.1


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

Предыдущее
От: Nikita Glukhov
Дата:
Сообщение: Re: jsonpath
Следующее
От: "Daniel Verite"
Дата:
Сообщение: Doc patch on psql output formats