diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2009-04-02 22:39:30 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2009-04-02 22:39:30 +0000 |
commit | 85369f888ec9af8ed573c589b7d6fe28015a6cb6 (patch) | |
tree | 8fffcb58938c6803b8389765fcf58a43204e0cad /src/backend/executor | |
parent | 0e550ff6174ebe8bab15b1218fa336e484513a61 (diff) | |
download | postgresql-85369f888ec9af8ed573c589b7d6fe28015a6cb6.tar.gz postgresql-85369f888ec9af8ed573c589b7d6fe28015a6cb6.zip |
Refactor ExecProject and associated routines so that fast-path code is used
for simple Var targetlist entries all the time, even when there are other
entries that are not simple Vars. Also, ensure that we prefetch attributes
(with slot_getsomeattrs) for all Vars in the targetlist, even those buried
within expressions. In combination these changes seem to significantly
reduce the runtime for cases where tlists are mostly but not exclusively
Vars. Per my proposal of yesterday.
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 150 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 198 |
2 files changed, 204 insertions, 144 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index d66bf4da822..21a9eb1753c 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.243 2009/03/27 18:30:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.244 2009/04/02 22:39:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -4966,6 +4966,7 @@ ExecCleanTargetListLength(List *targetlist) * prepared to deal with sets of result tuples. Otherwise, a return * of *isDone = ExprMultipleResult signifies a set element, and a return * of *isDone = ExprEndResult signifies end of the set of tuple. + * We assume that *isDone has been initialized to ExprSingleResult by caller. */ static bool ExecTargetList(List *targetlist, @@ -4987,9 +4988,6 @@ ExecTargetList(List *targetlist, /* * evaluate all the expressions in the target list */ - if (isDone) - *isDone = ExprSingleResult; /* until proven otherwise */ - haveDoneSets = false; /* any exhausted set exprs in tlist? */ foreach(tl, targetlist) @@ -5105,50 +5103,6 @@ ExecTargetList(List *targetlist, } /* - * ExecVariableList - * Evaluates a simple-Variable-list projection. - * - * Results are stored into the passed values and isnull arrays. - */ -static void -ExecVariableList(ProjectionInfo *projInfo, - Datum *values, - bool *isnull) -{ - ExprContext *econtext = projInfo->pi_exprContext; - int *varSlotOffsets = projInfo->pi_varSlotOffsets; - int *varNumbers = projInfo->pi_varNumbers; - int i; - - /* - * Force extraction of all input values that we need. - */ - if (projInfo->pi_lastInnerVar > 0) - slot_getsomeattrs(econtext->ecxt_innertuple, - projInfo->pi_lastInnerVar); - if (projInfo->pi_lastOuterVar > 0) - slot_getsomeattrs(econtext->ecxt_outertuple, - projInfo->pi_lastOuterVar); - if (projInfo->pi_lastScanVar > 0) - slot_getsomeattrs(econtext->ecxt_scantuple, - projInfo->pi_lastScanVar); - - /* - * Assign to result by direct extraction of fields from source slots ... a - * mite ugly, but fast ... - */ - for (i = list_length(projInfo->pi_targetlist) - 1; i >= 0; i--) - { - char *slotptr = ((char *) econtext) + varSlotOffsets[i]; - TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr); - int varNumber = varNumbers[i] - 1; - - values[i] = varSlot->tts_values[varNumber]; - isnull[i] = varSlot->tts_isnull[varNumber]; - } -} - -/* * ExecProject * * projects a tuple based on projection info and stores @@ -5165,6 +5119,8 @@ TupleTableSlot * ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) { TupleTableSlot *slot; + ExprContext *econtext; + int numSimpleVars; /* * sanity checks @@ -5175,6 +5131,11 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) * get the projection info we want */ slot = projInfo->pi_slot; + econtext = projInfo->pi_exprContext; + + /* Assume single result row until proven otherwise */ + if (isDone) + *isDone = ExprSingleResult; /* * Clear any former contents of the result slot. This makes it safe for @@ -5184,29 +5145,84 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone) ExecClearTuple(slot); /* - * form a new result tuple (if possible); if successful, mark the result - * slot as containing a valid virtual tuple + * Force extraction of all input values that we'll need. The + * Var-extraction loops below depend on this, and we are also prefetching + * all attributes that will be referenced in the generic expressions. + */ + if (projInfo->pi_lastInnerVar > 0) + slot_getsomeattrs(econtext->ecxt_innertuple, + projInfo->pi_lastInnerVar); + if (projInfo->pi_lastOuterVar > 0) + slot_getsomeattrs(econtext->ecxt_outertuple, + projInfo->pi_lastOuterVar); + if (projInfo->pi_lastScanVar > 0) + slot_getsomeattrs(econtext->ecxt_scantuple, + projInfo->pi_lastScanVar); + + /* + * Assign simple Vars to result by direct extraction of fields from source + * slots ... a mite ugly, but fast ... */ - if (projInfo->pi_isVarList) + numSimpleVars = projInfo->pi_numSimpleVars; + if (numSimpleVars > 0) { - /* simple Var list: this always succeeds with one result row */ - if (isDone) - *isDone = ExprSingleResult; - ExecVariableList(projInfo, - slot->tts_values, - slot->tts_isnull); - ExecStoreVirtualTuple(slot); + Datum *values = slot->tts_values; + bool *isnull = slot->tts_isnull; + int *varSlotOffsets = projInfo->pi_varSlotOffsets; + int *varNumbers = projInfo->pi_varNumbers; + int i; + + if (projInfo->pi_directMap) + { + /* especially simple case where vars go to output in order */ + for (i = 0; i < numSimpleVars; i++) + { + char *slotptr = ((char *) econtext) + varSlotOffsets[i]; + TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr); + int varNumber = varNumbers[i] - 1; + + values[i] = varSlot->tts_values[varNumber]; + isnull[i] = varSlot->tts_isnull[varNumber]; + } + } + else + { + /* we have to pay attention to varOutputCols[] */ + int *varOutputCols = projInfo->pi_varOutputCols; + + for (i = 0; i < numSimpleVars; i++) + { + char *slotptr = ((char *) econtext) + varSlotOffsets[i]; + TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr); + int varNumber = varNumbers[i] - 1; + int varOutputCol = varOutputCols[i] - 1; + + values[varOutputCol] = varSlot->tts_values[varNumber]; + isnull[varOutputCol] = varSlot->tts_isnull[varNumber]; + } + } } - else + + /* + * If there are any generic expressions, evaluate them. It's possible + * that there are set-returning functions in such expressions; if so + * and we have reached the end of the set, we return the result slot, + * which we already marked empty. + */ + if (projInfo->pi_targetlist) { - if (ExecTargetList(projInfo->pi_targetlist, - projInfo->pi_exprContext, - slot->tts_values, - slot->tts_isnull, - projInfo->pi_itemIsDone, - isDone)) - ExecStoreVirtualTuple(slot); + if (!ExecTargetList(projInfo->pi_targetlist, + econtext, + slot->tts_values, + slot->tts_isnull, + projInfo->pi_itemIsDone, + isDone)) + return slot; /* no more result rows, return empty slot */ } - return slot; + /* + * Successfully formed a result row. Mark the result slot as containing a + * valid virtual tuple. + */ + return ExecStoreVirtualTuple(slot); } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 995e1477e3a..4b3d92d48b8 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.157 2009/01/01 17:23:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.158 2009/04/02 22:39:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -46,6 +46,7 @@ #include "access/heapam.h" #include "catalog/index.h" #include "executor/execdebug.h" +#include "nodes/nodeFuncs.h" #include "parser/parsetree.h" #include "utils/memutils.h" #include "utils/relcache.h" @@ -66,6 +67,7 @@ int NIndexTupleInserted; int NIndexTupleProcessed; +static bool get_last_attnums(Node *node, ProjectionInfo *projInfo); static void ShutdownExprContext(ExprContext *econtext); @@ -559,121 +561,163 @@ ExecBuildProjectionInfo(List *targetList, TupleDesc inputDesc) { ProjectionInfo *projInfo = makeNode(ProjectionInfo); - int len; - bool isVarList; + int len = ExecTargetListLength(targetList); + int *workspace; + int *varSlotOffsets; + int *varNumbers; + int *varOutputCols; + List *exprlist; + int numSimpleVars; + bool directMap; ListCell *tl; - len = ExecTargetListLength(targetList); - - projInfo->pi_targetlist = targetList; projInfo->pi_exprContext = econtext; projInfo->pi_slot = slot; + /* since these are all int arrays, we need do just one palloc */ + workspace = (int *) palloc(len * 3 * sizeof(int)); + projInfo->pi_varSlotOffsets = varSlotOffsets = workspace; + projInfo->pi_varNumbers = varNumbers = workspace + len; + projInfo->pi_varOutputCols = varOutputCols = workspace + len * 2; + projInfo->pi_lastInnerVar = 0; + projInfo->pi_lastOuterVar = 0; + projInfo->pi_lastScanVar = 0; /* - * Determine whether the target list consists entirely of simple Var - * references (ie, references to non-system attributes) that match the - * input. If so, we can use the simpler ExecVariableList instead of - * ExecTargetList. (Note: if there is a type mismatch then ExecEvalVar - * will probably throw an error at runtime, but we leave that to it.) + * We separate the target list elements into simple Var references and + * expressions which require the full ExecTargetList machinery. To be + * a simple Var, a Var has to be a user attribute and not mismatch the + * inputDesc. (Note: if there is a type mismatch then ExecEvalVar will + * probably throw an error at runtime, but we leave that to it.) */ - isVarList = true; + exprlist = NIL; + numSimpleVars = 0; + directMap = true; foreach(tl, targetList) { GenericExprState *gstate = (GenericExprState *) lfirst(tl); Var *variable = (Var *) gstate->arg->expr; - Form_pg_attribute attr; + bool isSimpleVar = false; - if (variable == NULL || - !IsA(variable, Var) || - variable->varattno <= 0) - { - isVarList = false; - break; - } - if (!inputDesc) - continue; /* can't check type, assume OK */ - if (variable->varattno > inputDesc->natts) + if (variable != NULL && + IsA(variable, Var) && + variable->varattno > 0) { - isVarList = false; - break; - } - attr = inputDesc->attrs[variable->varattno - 1]; - if (attr->attisdropped || variable->vartype != attr->atttypid) - { - isVarList = false; - break; - } - } - projInfo->pi_isVarList = isVarList; - - if (isVarList) - { - int *varSlotOffsets; - int *varNumbers; - AttrNumber lastInnerVar = 0; - AttrNumber lastOuterVar = 0; - AttrNumber lastScanVar = 0; + if (!inputDesc) + isSimpleVar = true; /* can't check type, assume OK */ + else if (variable->varattno <= inputDesc->natts) + { + Form_pg_attribute attr; - projInfo->pi_itemIsDone = NULL; /* not needed */ - projInfo->pi_varSlotOffsets = varSlotOffsets = (int *) - palloc0(len * sizeof(int)); - projInfo->pi_varNumbers = varNumbers = (int *) - palloc0(len * sizeof(int)); + attr = inputDesc->attrs[variable->varattno - 1]; + if (!attr->attisdropped && variable->vartype == attr->atttypid) + isSimpleVar = true; + } + } - /* - * Set up the data needed by ExecVariableList. The slots in which the - * variables can be found at runtime are denoted by the offsets of - * their slot pointers within the econtext. This rather grotty - * representation is needed because the caller may not have given us - * the real econtext yet (see hacks in nodeSubplan.c). - */ - foreach(tl, targetList) + if (isSimpleVar) { - GenericExprState *gstate = (GenericExprState *) lfirst(tl); - Var *variable = (Var *) gstate->arg->expr; - AttrNumber attnum = variable->varattno; TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr; - AttrNumber resind = tle->resno - 1; + AttrNumber attnum = variable->varattno; - Assert(resind >= 0 && resind < len); - varNumbers[resind] = attnum; + varNumbers[numSimpleVars] = attnum; + varOutputCols[numSimpleVars] = tle->resno; + if (tle->resno != numSimpleVars+1) + directMap = false; switch (variable->varno) { case INNER: - varSlotOffsets[resind] = offsetof(ExprContext, - ecxt_innertuple); - lastInnerVar = Max(lastInnerVar, attnum); + varSlotOffsets[numSimpleVars] = offsetof(ExprContext, + ecxt_innertuple); + if (projInfo->pi_lastInnerVar < attnum) + projInfo->pi_lastInnerVar = attnum; break; case OUTER: - varSlotOffsets[resind] = offsetof(ExprContext, - ecxt_outertuple); - lastOuterVar = Max(lastOuterVar, attnum); + varSlotOffsets[numSimpleVars] = offsetof(ExprContext, + ecxt_outertuple); + if (projInfo->pi_lastOuterVar < attnum) + projInfo->pi_lastOuterVar = attnum; break; default: - varSlotOffsets[resind] = offsetof(ExprContext, - ecxt_scantuple); - lastScanVar = Max(lastScanVar, attnum); + varSlotOffsets[numSimpleVars] = offsetof(ExprContext, + ecxt_scantuple); + if (projInfo->pi_lastScanVar < attnum) + projInfo->pi_lastScanVar = attnum; break; } + numSimpleVars++; + } + else + { + /* Not a simple variable, add it to generic targetlist */ + exprlist = lappend(exprlist, gstate); + /* Examine expr to include contained Vars in lastXXXVar counts */ + get_last_attnums((Node *) variable, projInfo); } - projInfo->pi_lastInnerVar = lastInnerVar; - projInfo->pi_lastOuterVar = lastOuterVar; - projInfo->pi_lastScanVar = lastScanVar; } + projInfo->pi_targetlist = exprlist; + projInfo->pi_numSimpleVars = numSimpleVars; + projInfo->pi_directMap = directMap; + + if (exprlist == NIL) + projInfo->pi_itemIsDone = NULL; /* not needed */ else - { projInfo->pi_itemIsDone = (ExprDoneCond *) palloc(len * sizeof(ExprDoneCond)); - projInfo->pi_varSlotOffsets = NULL; - projInfo->pi_varNumbers = NULL; - } return projInfo; } +/* + * get_last_attnums: expression walker for ExecBuildProjectionInfo + * + * Update the lastXXXVar counts to be at least as large as the largest + * attribute numbers found in the expression + */ +static bool +get_last_attnums(Node *node, ProjectionInfo *projInfo) +{ + if (node == NULL) + return false; + if (IsA(node, Var)) + { + Var *variable = (Var *) node; + AttrNumber attnum = variable->varattno; + + switch (variable->varno) + { + case INNER: + if (projInfo->pi_lastInnerVar < attnum) + projInfo->pi_lastInnerVar = attnum; + break; + + case OUTER: + if (projInfo->pi_lastOuterVar < attnum) + projInfo->pi_lastOuterVar = attnum; + break; + + default: + if (projInfo->pi_lastScanVar < attnum) + projInfo->pi_lastScanVar = attnum; + break; + } + return false; + } + /* + * Don't examine the arguments of Aggrefs or WindowFuncs, because those + * do not represent expressions to be evaluated within the overall + * targetlist's econtext. + */ + if (IsA(node, Aggref)) + return false; + if (IsA(node, WindowFunc)) + return false; + return expression_tree_walker(node, get_last_attnums, + (void *) projInfo); +} + /* ---------------- * ExecAssignProjectionInfo * |