1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Avoid projecting tuples unnecessarily in Gather and Gather Merge.

It's most often the case that the target list for the Gather (Merge)
node matches the target list supplied by the underlying plan node;
when this is so, we can avoid the overhead of projecting.

This depends on commit f455e1125e for
proper functioning.

Idea by Andres Freund.  Patch by me.  Review by Amit Kapila.

Discussion: http://postgr.es/m/CA+TgmoZ0ZL=cesZFq8c9NnfK6bqy-wwUd3_74iYGodYrSoQ7Fw@mail.gmail.com
This commit is contained in:
Robert Haas
2017-11-25 10:49:17 -05:00
parent 0f2458ff5f
commit b10967eddf
5 changed files with 110 additions and 87 deletions

View File

@ -23,8 +23,6 @@
#include "utils/memutils.h"
static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
/*
* ExecScanFetch -- check interrupts & fetch next potential tuple
@ -237,8 +235,9 @@ void
ExecAssignScanProjectionInfo(ScanState *node)
{
Scan *scan = (Scan *) node->ps.plan;
TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid);
}
/*
@ -248,75 +247,9 @@ ExecAssignScanProjectionInfo(ScanState *node)
void
ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
{
Scan *scan = (Scan *) node->ps.plan;
TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
if (tlist_matches_tupdesc(&node->ps,
scan->plan.targetlist,
varno,
node->ss_ScanTupleSlot->tts_tupleDescriptor))
node->ps.ps_ProjInfo = NULL;
else
ExecAssignProjectionInfo(&node->ps,
node->ss_ScanTupleSlot->tts_tupleDescriptor);
}
static bool
tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
{
int numattrs = tupdesc->natts;
int attrno;
bool hasoid;
ListCell *tlist_item = list_head(tlist);
/* Check the tlist attributes */
for (attrno = 1; attrno <= numattrs; attrno++)
{
Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
Var *var;
if (tlist_item == NULL)
return false; /* tlist too short */
var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
if (!var || !IsA(var, Var))
return false; /* tlist item not a Var */
/* if these Asserts fail, planner messed up */
Assert(var->varno == varno);
Assert(var->varlevelsup == 0);
if (var->varattno != attrno)
return false; /* out of order */
if (att_tup->attisdropped)
return false; /* table contains dropped columns */
/*
* Note: usually the Var's type should match the tupdesc exactly, but
* in situations involving unions of columns that have different
* typmods, the Var may have come from above the union and hence have
* typmod -1. This is a legitimate situation since the Var still
* describes the column, just not as exactly as the tupdesc does. We
* could change the planner to prevent it, but it'd then insert
* projection steps just to convert from specific typmod to typmod -1,
* which is pretty silly.
*/
if (var->vartype != att_tup->atttypid ||
(var->vartypmod != att_tup->atttypmod &&
var->vartypmod != -1))
return false; /* type mismatch */
tlist_item = lnext(tlist_item);
}
if (tlist_item)
return false; /* tlist too long */
/*
* If the plan context requires a particular hasoid setting, then that has
* to match, too.
*/
if (ExecContextForcesOids(ps, &hasoid) &&
hasoid != tupdesc->tdhasoid)
return false;
return true;
ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno);
}
/*