diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-03 15:07:08 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-03 15:07:08 +0000 |
commit | 4cff59d8d540c441fb0c22dfaa517bc25aa5f794 (patch) | |
tree | 88b4c216d219582904d3d9d6a236bb9468fe148c /src/backend/optimizer/plan/createplan.c | |
parent | 0d3e36b6687ae601551fb8047c10a68f2d6fb565 (diff) | |
download | postgresql-4cff59d8d540c441fb0c22dfaa517bc25aa5f794.tar.gz postgresql-4cff59d8d540c441fb0c22dfaa517bc25aa5f794.zip |
Tweak planner and executor to avoid doing ExecProject() in table scan
nodes where it's not really necessary. In many cases where the scan node
is not the topmost plan node (eg, joins, aggregation), it's possible to
just return the table tuple directly instead of generating an intermediate
projection tuple. In preliminary testing, this reduced the CPU time
needed for 'SELECT COUNT(*) FROM foo' by about 10%.
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 78 |
1 files changed, 73 insertions, 5 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index eb7e922d9a1..d78dd2c1e83 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.133 2003/01/22 00:07:00 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.134 2003/02/03 15:07:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,6 +34,7 @@ static Scan *create_scan_plan(Query *root, Path *best_path); +static bool use_physical_tlist(RelOptInfo *rel); static Join *create_join_plan(Query *root, JoinPath *best_path); static Append *create_append_plan(Query *root, AppendPath *best_path); static Result *create_result_plan(Query *root, ResultPath *best_path); @@ -185,15 +186,41 @@ create_plan(Query *root, Path *best_path) static Scan * create_scan_plan(Query *root, Path *best_path) { - Scan *plan; - List *tlist = best_path->parent->targetlist; + RelOptInfo *rel = best_path->parent; + List *tlist; List *scan_clauses; + Scan *plan; + + /* + * For table scans, rather than using the relation targetlist (which is + * only those Vars actually needed by the query), we prefer to generate a + * tlist containing all Vars in order. This will allow the executor to + * optimize away projection of the table tuples, if possible. (Note that + * planner.c may replace the tlist we generate here, forcing projection to + * occur.) + */ + if (use_physical_tlist(rel)) + { + int resdomno = 1; + List *v; + + tlist = NIL; + foreach(v, rel->varlist) + { + Var *var = (Var *) lfirst(v); + + tlist = lappend(tlist, create_tl_element(var, resdomno)); + resdomno++; + } + } + else + tlist = rel->targetlist; /* * Extract the relevant restriction clauses from the parent relation; * the executor must apply all these restrictions during the scan. */ - scan_clauses = get_actual_clauses(best_path->parent->baserestrictinfo); + scan_clauses = get_actual_clauses(rel->baserestrictinfo); /* Sort clauses into best execution order */ scan_clauses = order_qual_clauses(root, scan_clauses); @@ -242,6 +269,47 @@ create_scan_plan(Query *root, Path *best_path) } /* + * use_physical_tlist + * Decide whether to use a tlist matching relation structure, + * rather than only those Vars actually referenced. + */ +static bool +use_physical_tlist(RelOptInfo *rel) +{ + List *t; + + /* + * Currently, can't do this for subquery or function scans. (This + * is mainly because we don't set up the necessary info when creating + * their RelOptInfo nodes.) + */ + if (rel->rtekind != RTE_RELATION) + return false; + /* + * Can't do it with inheritance cases either (mainly because Append + * doesn't project). + */ + if (rel->reloptkind != RELOPT_BASEREL) + return false; + /* + * Can't do it if any system columns are requested, either. (This could + * possibly be fixed but would take some fragile assumptions in setrefs.c, + * I think.) + */ + foreach(t, rel->targetlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(t); + Var *var = (Var *) tle->expr; + + if (!var || !IsA(var, Var)) + return false; /* probably can't happen */ + if (var->varattno <= 0) + return false; /* system column! */ + } + return true; +} + +/* * create_join_plan * Create a join plan for 'best_path' and (recursively) plans for its * inner and outer paths. @@ -399,7 +467,7 @@ create_material_plan(Query *root, MaterialPath *best_path) subplan = create_plan(root, best_path->subpath); - plan = make_material(best_path->path.parent->targetlist, subplan); + plan = make_material(subplan->targetlist, subplan); copy_path_costsize(&plan->plan, (Path *) best_path); |