mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Avoid O(N^2) cost in ExecFindRowMark().
If there are many ExecRowMark structs, we spent O(N^2) time in ExecFindRowMark during executor startup. Once upon a time this was not of great concern, but the addition of native partitioning has squeezed out enough other costs that this can become the dominant overhead in some use-cases for tables with many partitions. To fix, simply replace that List data structure with an array. This adds a little bit of cost to execCurrentOf(), but not much, and anyway that code path is neither of large importance nor very efficient now. If we ever decide it is a bottleneck, constructing a hash table for lookup-by-tableoid would likely be the thing to do. Per complaint from Amit Langote, though this is different from his fix proposal. Discussion: https://postgr.es/m/468c85d9-540e-66a2-1dde-fec2b741e688@lab.ntt.co.jp
This commit is contained in:
@ -909,61 +909,68 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, build the ExecRowMark list from the PlanRowMark(s), if any.
|
||||
* Next, build the ExecRowMark array from the PlanRowMark(s), if any.
|
||||
*/
|
||||
estate->es_rowMarks = NIL;
|
||||
foreach(l, plannedstmt->rowMarks)
|
||||
if (plannedstmt->rowMarks)
|
||||
{
|
||||
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
|
||||
Oid relid;
|
||||
Relation relation;
|
||||
ExecRowMark *erm;
|
||||
|
||||
/* ignore "parent" rowmarks; they are irrelevant at runtime */
|
||||
if (rc->isParent)
|
||||
continue;
|
||||
|
||||
/* get relation's OID (will produce InvalidOid if subquery) */
|
||||
relid = exec_rt_fetch(rc->rti, estate)->relid;
|
||||
|
||||
/* open relation, if we need to access it for this mark type */
|
||||
switch (rc->markType)
|
||||
estate->es_rowmarks = (ExecRowMark **)
|
||||
palloc0(estate->es_range_table_size * sizeof(ExecRowMark *));
|
||||
foreach(l, plannedstmt->rowMarks)
|
||||
{
|
||||
case ROW_MARK_EXCLUSIVE:
|
||||
case ROW_MARK_NOKEYEXCLUSIVE:
|
||||
case ROW_MARK_SHARE:
|
||||
case ROW_MARK_KEYSHARE:
|
||||
case ROW_MARK_REFERENCE:
|
||||
relation = ExecGetRangeTableRelation(estate, rc->rti);
|
||||
break;
|
||||
case ROW_MARK_COPY:
|
||||
/* no physical table access is required */
|
||||
relation = NULL;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized markType: %d", rc->markType);
|
||||
relation = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
|
||||
Oid relid;
|
||||
Relation relation;
|
||||
ExecRowMark *erm;
|
||||
|
||||
/* ignore "parent" rowmarks; they are irrelevant at runtime */
|
||||
if (rc->isParent)
|
||||
continue;
|
||||
|
||||
/* get relation's OID (will produce InvalidOid if subquery) */
|
||||
relid = exec_rt_fetch(rc->rti, estate)->relid;
|
||||
|
||||
/* open relation, if we need to access it for this mark type */
|
||||
switch (rc->markType)
|
||||
{
|
||||
case ROW_MARK_EXCLUSIVE:
|
||||
case ROW_MARK_NOKEYEXCLUSIVE:
|
||||
case ROW_MARK_SHARE:
|
||||
case ROW_MARK_KEYSHARE:
|
||||
case ROW_MARK_REFERENCE:
|
||||
relation = ExecGetRangeTableRelation(estate, rc->rti);
|
||||
break;
|
||||
case ROW_MARK_COPY:
|
||||
/* no physical table access is required */
|
||||
relation = NULL;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized markType: %d", rc->markType);
|
||||
relation = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check that relation is a legal target for marking */
|
||||
if (relation)
|
||||
CheckValidRowMarkRel(relation, rc->markType);
|
||||
|
||||
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
|
||||
erm->relation = relation;
|
||||
erm->relid = relid;
|
||||
erm->rti = rc->rti;
|
||||
erm->prti = rc->prti;
|
||||
erm->rowmarkId = rc->rowmarkId;
|
||||
erm->markType = rc->markType;
|
||||
erm->strength = rc->strength;
|
||||
erm->waitPolicy = rc->waitPolicy;
|
||||
erm->ermActive = false;
|
||||
ItemPointerSetInvalid(&(erm->curCtid));
|
||||
erm->ermExtra = NULL;
|
||||
|
||||
Assert(erm->rti > 0 && erm->rti <= estate->es_range_table_size &&
|
||||
estate->es_rowmarks[erm->rti - 1] == NULL);
|
||||
|
||||
estate->es_rowmarks[erm->rti - 1] = erm;
|
||||
}
|
||||
|
||||
/* Check that relation is a legal target for marking */
|
||||
if (relation)
|
||||
CheckValidRowMarkRel(relation, rc->markType);
|
||||
|
||||
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
|
||||
erm->relation = relation;
|
||||
erm->relid = relid;
|
||||
erm->rti = rc->rti;
|
||||
erm->prti = rc->prti;
|
||||
erm->rowmarkId = rc->rowmarkId;
|
||||
erm->markType = rc->markType;
|
||||
erm->strength = rc->strength;
|
||||
erm->waitPolicy = rc->waitPolicy;
|
||||
erm->ermActive = false;
|
||||
ItemPointerSetInvalid(&(erm->curCtid));
|
||||
erm->ermExtra = NULL;
|
||||
|
||||
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2394,13 +2401,12 @@ ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo)
|
||||
ExecRowMark *
|
||||
ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
foreach(lc, estate->es_rowMarks)
|
||||
if (rti > 0 && rti <= estate->es_range_table_size &&
|
||||
estate->es_rowmarks != NULL)
|
||||
{
|
||||
ExecRowMark *erm = (ExecRowMark *) lfirst(lc);
|
||||
ExecRowMark *erm = estate->es_rowmarks[rti - 1];
|
||||
|
||||
if (erm->rti == rti)
|
||||
if (erm)
|
||||
return erm;
|
||||
}
|
||||
if (!missing_ok)
|
||||
@ -3131,6 +3137,7 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
|
||||
estate->es_range_table_array = parentestate->es_range_table_array;
|
||||
estate->es_range_table_size = parentestate->es_range_table_size;
|
||||
estate->es_relations = parentestate->es_relations;
|
||||
estate->es_rowmarks = parentestate->es_rowmarks;
|
||||
estate->es_plannedstmt = parentestate->es_plannedstmt;
|
||||
estate->es_junkFilter = parentestate->es_junkFilter;
|
||||
estate->es_output_cid = parentestate->es_output_cid;
|
||||
@ -3148,7 +3155,6 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree)
|
||||
}
|
||||
/* es_result_relation_info must NOT be copied */
|
||||
/* es_trig_target_relations must NOT be copied */
|
||||
estate->es_rowMarks = parentestate->es_rowMarks;
|
||||
estate->es_top_eflags = parentestate->es_top_eflags;
|
||||
estate->es_instrument = parentestate->es_instrument;
|
||||
/* es_auxmodifytables must NOT be copied */
|
||||
|
Reference in New Issue
Block a user