Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita5cd70d

Browse files
committed
Improve performance of EXPLAIN with large range tables.
As of 9.3, ruleutils.c goes to some lengths to ensure that table and columnaliases used in its output are unique. Of course this takes more time thanwas required before, which in itself isn't fatal. However, EXPLAIN was setup so that recalculation of the unique aliases was repeated for eachsubexpression printed in a plan. That results in O(N^2) time and memoryconsumption for large plan trees, which did not happen in older branches.Fortunately, the expensive work is the same across a whole plan tree,so there is no need to repeat it; we can do most of the initializationjust once per query and re-use it for each subexpression. This buysback most (not all) of the performance loss since 9.2.We need an extra ExplainState field to hold the precalculated deparsecontext. That's no problem in HEAD, but in the back branches, expandingsizeof(ExplainState) seems risky because third-party extensions mighthave local variables of that struct type. So, in 9.4 and 9.3, introducean auxiliary struct to keep sizeof(ExplainState) the same. We shouldrefactor the APIs to avoid such local variables in future, but that'smaterial for a separate HEAD-only commit.Per gripe from Alexey Bashtanov. Back-patch to 9.3 where the issuewas introduced.
1 parent0b49642 commita5cd70d

File tree

4 files changed

+66
-38
lines changed

4 files changed

+66
-38
lines changed

‎src/backend/commands/explain.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,8 @@ ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
563563
es->rtable=queryDesc->plannedstmt->rtable;
564564
ExplainPreScanNode(queryDesc->planstate,&rels_used);
565565
es->rtable_names=select_rtable_names_for_explain(es->rtable,rels_used);
566+
es->deparse_cxt=deparse_context_for_plan_rtable(es->rtable,
567+
es->rtable_names);
566568
ExplainNode(queryDesc->planstate,NIL,NULL,NULL,es);
567569
}
568570

@@ -1678,10 +1680,9 @@ show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
16781680
return;
16791681

16801682
/* Set up deparsing context */
1681-
context=deparse_context_for_planstate((Node*)planstate,
1682-
ancestors,
1683-
es->rtable,
1684-
es->rtable_names);
1683+
context=set_deparse_context_planstate(es->deparse_cxt,
1684+
(Node*)planstate,
1685+
ancestors);
16851686
useprefix=list_length(es->rtable)>1;
16861687

16871688
/* Deparse each result column (we now include resjunk ones) */
@@ -1710,10 +1711,9 @@ show_expression(Node *node, const char *qlabel,
17101711
char*exprstr;
17111712

17121713
/* Set up deparsing context */
1713-
context=deparse_context_for_planstate((Node*)planstate,
1714-
ancestors,
1715-
es->rtable,
1716-
es->rtable_names);
1714+
context=set_deparse_context_planstate(es->deparse_cxt,
1715+
(Node*)planstate,
1716+
ancestors);
17171717

17181718
/* Deparse the expression */
17191719
exprstr=deparse_expression(node,context,useprefix, false);
@@ -1855,10 +1855,9 @@ show_sort_group_keys(PlanState *planstate, const char *qlabel,
18551855
return;
18561856

18571857
/* Set up deparsing context */
1858-
context=deparse_context_for_planstate((Node*)planstate,
1859-
ancestors,
1860-
es->rtable,
1861-
es->rtable_names);
1858+
context=set_deparse_context_planstate(es->deparse_cxt,
1859+
(Node*)planstate,
1860+
ancestors);
18621861
useprefix= (list_length(es->rtable)>1||es->verbose);
18631862

18641863
for (keyno=0;keyno<nkeys;keyno++)

‎src/backend/utils/adt/ruleutils.c

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,7 +2520,43 @@ deparse_context_for(const char *aliasname, Oid relid)
25202520
}
25212521

25222522
/*
2523-
* deparse_context_for_planstate- Build deparse context for a plan
2523+
* deparse_context_for_plan_rtable - Build deparse context for a plan's rtable
2524+
*
2525+
* When deparsing an expression in a Plan tree, we use the plan's rangetable
2526+
* to resolve names of simple Vars. The initialization of column names for
2527+
* this is rather expensive if the rangetable is large, and it'll be the same
2528+
* for every expression in the Plan tree; so we do it just once and re-use
2529+
* the result of this function for each expression. (Note that the result
2530+
* is not usable until set_deparse_context_planstate() is applied to it.)
2531+
*
2532+
* In addition to the plan's rangetable list, pass the per-RTE alias names
2533+
* assigned by a previous call to select_rtable_names_for_explain.
2534+
*/
2535+
List*
2536+
deparse_context_for_plan_rtable(List*rtable,List*rtable_names)
2537+
{
2538+
deparse_namespace*dpns;
2539+
2540+
dpns= (deparse_namespace*)palloc0(sizeof(deparse_namespace));
2541+
2542+
/* Initialize fields that stay the same across the whole plan tree */
2543+
dpns->rtable=rtable;
2544+
dpns->rtable_names=rtable_names;
2545+
dpns->ctes=NIL;
2546+
2547+
/*
2548+
* Set up column name aliases. We will get rather bogus results for join
2549+
* RTEs, but that doesn't matter because plan trees don't contain any join
2550+
* alias Vars.
2551+
*/
2552+
set_simple_column_names(dpns);
2553+
2554+
/* Return a one-deep namespace stack */
2555+
returnlist_make1(dpns);
2556+
}
2557+
2558+
/*
2559+
* set_deparse_context_planstate- Specify Plan node containing expression
25242560
*
25252561
* When deparsing an expression in a Plan tree, we might have to resolve
25262562
* OUTER_VAR, INNER_VAR, or INDEX_VAR references. To do this, the caller must
@@ -2533,43 +2569,34 @@ deparse_context_for(const char *aliasname, Oid relid)
25332569
* fields, which won't contain INDEX_VAR Vars.)
25342570
*
25352571
* Note: planstate really ought to be declared as "PlanState *", but we use
2536-
* "Node *" to avoid having to include execnodes.h inbuiltins.h.
2572+
* "Node *" to avoid having to include execnodes.h inruleutils.h.
25372573
*
25382574
* The ancestors list is a list of the PlanState's parent PlanStates, the
25392575
* most-closely-nested first. This is needed to resolve PARAM_EXEC Params.
25402576
* Note we assume that all the PlanStates share the same rtable.
25412577
*
2542-
* The plan's rangetable list must also be passed, along with the per-RTE
2543-
* alias names assigned by a previous call to select_rtable_names_for_explain.
2544-
* (We use the rangetable to resolve simple Vars, but the plan inputs are
2545-
* necessary for Vars with special varnos.)
2578+
* Once this function has been called, deparse_expression() can be called on
2579+
* subsidiary expression(s) of the specified PlanState node. To deparse
2580+
* expressions of a different Plan node in the same Plan tree, re-call this
2581+
* function to identify the new parent Plan node.
2582+
*
2583+
* The result is the same List passed in; this is a notational convenience.
25462584
*/
25472585
List*
2548-
deparse_context_for_planstate(Node*planstate,List*ancestors,
2549-
List*rtable,List*rtable_names)
2586+
set_deparse_context_planstate(List*dpcontext,
2587+
Node*planstate,List*ancestors)
25502588
{
25512589
deparse_namespace*dpns;
25522590

2553-
dpns= (deparse_namespace*)palloc0(sizeof(deparse_namespace));
2554-
2555-
/* Initialize fields that stay the same across the whole plan tree */
2556-
dpns->rtable=rtable;
2557-
dpns->rtable_names=rtable_names;
2558-
dpns->ctes=NIL;
2559-
2560-
/*
2561-
* Set up column name aliases. We will get rather bogus results for join
2562-
* RTEs, but that doesn't matter because plan trees don't contain any join
2563-
* alias Vars.
2564-
*/
2565-
set_simple_column_names(dpns);
2591+
/* Should always have one-entry namespace list for Plan deparsing */
2592+
Assert(list_length(dpcontext)==1);
2593+
dpns= (deparse_namespace*)linitial(dpcontext);
25662594

25672595
/* Set our attention on the specific plan node passed in */
25682596
set_deparse_planstate(dpns, (PlanState*)planstate);
25692597
dpns->ancestors=ancestors;
25702598

2571-
/* Return a one-deep namespace stack */
2572-
returnlist_make1(dpns);
2599+
returndpcontext;
25732600
}
25742601

25752602
/*

‎src/include/commands/explain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ typedef struct ExplainState
4141
List*rtable_names;/* alias names for RTEs */
4242
intindent;/* current indentation level */
4343
List*grouping_stack;/* format-specific grouping state */
44+
List*deparse_cxt;/* context list for deparsing expressions */
4445
}ExplainState;
4546

4647
/* Hook for plugins to get control in ExplainOneQuery() */

‎src/include/utils/ruleutils.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* src/include/ruleutils.h
9+
* src/include/utils/ruleutils.h
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -25,8 +25,9 @@ extern char *pg_get_constraintdef_string(Oid constraintId);
2525
externchar*deparse_expression(Node*expr,List*dpcontext,
2626
boolforceprefix,boolshowimplicit);
2727
externList*deparse_context_for(constchar*aliasname,Oidrelid);
28-
externList*deparse_context_for_planstate(Node*planstate,List*ancestors,
29-
List*rtable,List*rtable_names);
28+
externList*deparse_context_for_plan_rtable(List*rtable,List*rtable_names);
29+
externList*set_deparse_context_planstate(List*dpcontext,
30+
Node*planstate,List*ancestors);
3031
externList*select_rtable_names_for_explain(List*rtable,
3132
Bitmapset*rels_used);
3233
externchar*generate_collation_name(Oidcollid);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp