1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Add TID Range Scans to support efficient scanning ranges of TIDs

This adds a new executor node named TID Range Scan.  The query planner
will generate paths for TID Range scans when quals are discovered on base
relations which search for ranges on the table's ctid column.  These
ranges may be open at either end. For example, WHERE ctid >= '(10,0)';
will return all tuples on page 10 and over.

To support this, two new optional callback functions have been added to
table AM.  scan_set_tidrange is used to set the scan range to just the
given range of TIDs.  scan_getnextslot_tidrange fetches the next tuple
in the given range.

For AMs were scanning ranges of TIDs would not make sense, these functions
can be set to NULL in the TableAmRoutine.  The query planner won't
generate TID Range Scan Paths in that case.

Author: Edmund Horner, David Rowley
Reviewed-by: David Rowley, Tomas Vondra, Tom Lane, Andres Freund, Zhihong Yu
Discussion: https://postgr.es/m/CAMyN-kB-nFTkF=VA_JPwFNo08S0d-Yk0F741S2B7LDmYAi8eyA@mail.gmail.com
This commit is contained in:
David Rowley
2021-02-27 22:59:36 +13:00
parent f4adc41c4f
commit bb437f995d
36 changed files with 1654 additions and 22 deletions

View File

@ -129,6 +129,10 @@ static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
static void bitmap_subplan_mark_shared(Plan *plan);
static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
List *tlist, List *scan_clauses);
static TidRangeScan *create_tidrangescan_plan(PlannerInfo *root,
TidRangePath *best_path,
List *tlist,
List *scan_clauses);
static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root,
SubqueryScanPath *best_path,
List *tlist, List *scan_clauses);
@ -193,6 +197,8 @@ static BitmapHeapScan *make_bitmap_heapscan(List *qptlist,
Index scanrelid);
static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tidquals);
static TidRangeScan *make_tidrangescan(List *qptlist, List *qpqual,
Index scanrelid, List *tidrangequals);
static SubqueryScan *make_subqueryscan(List *qptlist,
List *qpqual,
Index scanrelid,
@ -384,6 +390,7 @@ create_plan_recurse(PlannerInfo *root, Path *best_path, int flags)
case T_IndexOnlyScan:
case T_BitmapHeapScan:
case T_TidScan:
case T_TidRangeScan:
case T_SubqueryScan:
case T_FunctionScan:
case T_TableFuncScan:
@ -679,6 +686,13 @@ create_scan_plan(PlannerInfo *root, Path *best_path, int flags)
scan_clauses);
break;
case T_TidRangeScan:
plan = (Plan *) create_tidrangescan_plan(root,
(TidRangePath *) best_path,
tlist,
scan_clauses);
break;
case T_SubqueryScan:
plan = (Plan *) create_subqueryscan_plan(root,
(SubqueryScanPath *) best_path,
@ -3436,6 +3450,71 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
return scan_plan;
}
/*
* create_tidrangescan_plan
* Returns a tidrangescan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static TidRangeScan *
create_tidrangescan_plan(PlannerInfo *root, TidRangePath *best_path,
List *tlist, List *scan_clauses)
{
TidRangeScan *scan_plan;
Index scan_relid = best_path->path.parent->relid;
List *tidrangequals = best_path->tidrangequals;
/* it should be a base rel... */
Assert(scan_relid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION);
/*
* The qpqual list must contain all restrictions not enforced by the
* tidrangequals list. tidrangequals has AND semantics, so we can simply
* remove any qual that appears in it.
*/
{
List *qpqual = NIL;
ListCell *l;
foreach(l, scan_clauses)
{
RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
if (rinfo->pseudoconstant)
continue; /* we may drop pseudoconstants here */
if (list_member_ptr(tidrangequals, rinfo))
continue; /* simple duplicate */
qpqual = lappend(qpqual, rinfo);
}
scan_clauses = qpqual;
}
/* Sort clauses into best execution order */
scan_clauses = order_qual_clauses(root, scan_clauses);
/* Reduce RestrictInfo lists to bare expressions; ignore pseudoconstants */
tidrangequals = extract_actual_clauses(tidrangequals, false);
scan_clauses = extract_actual_clauses(scan_clauses, false);
/* Replace any outer-relation variables with nestloop params */
if (best_path->path.param_info)
{
tidrangequals = (List *)
replace_nestloop_params(root, (Node *) tidrangequals);
scan_clauses = (List *)
replace_nestloop_params(root, (Node *) scan_clauses);
}
scan_plan = make_tidrangescan(tlist,
scan_clauses,
scan_relid,
tidrangequals);
copy_generic_path_info(&scan_plan->scan.plan, &best_path->path);
return scan_plan;
}
/*
* create_subqueryscan_plan
* Returns a subqueryscan plan for the base relation scanned by 'best_path'
@ -5369,6 +5448,25 @@ make_tidscan(List *qptlist,
return node;
}
static TidRangeScan *
make_tidrangescan(List *qptlist,
List *qpqual,
Index scanrelid,
List *tidrangequals)
{
TidRangeScan *node = makeNode(TidRangeScan);
Plan *plan = &node->scan.plan;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->tidrangequals = tidrangequals;
return node;
}
static SubqueryScan *
make_subqueryscan(List *qptlist,
List *qpqual,