Align columnar path costing functions (#5239)

* Rename RecostColumnarPaths to CostColumnarPaths

* Rename RecostColumnarIndexPath to CostColumnarIndexPath

* Reorder args of CostColumnarScan to align with other two costing functions

* Not adjust index scan start-up cost

* Rename ColumnarIndexScanAddTotalCost to ColumnarIndexScanAdditionalCost

* Reflect that index scan will at least read one stripe in totalCost calculation

* Organize declarations in columnar_customscan.c
pull/5235/head
Onur Tirtir 2021-09-03 19:37:42 +03:00 committed by GitHub
parent cc58b58f73
commit 2b71263e40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 70 deletions

View File

@ -61,42 +61,46 @@ typedef struct ColumnarScanState
typedef bool (*PathPredicate)(Path *path); typedef bool (*PathPredicate)(Path *path);
static void ColumnarSetRelPathlistHook(PlannerInfo *root, RelOptInfo *rel, Index rti, /* functions to cost paths in-place */
RangeTblEntry *rte); static void CostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId);
static void RemovePathsByPredicate(RelOptInfo *rel, PathPredicate removePathPredicate); static void CostColumnarIndexPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
static bool IsNotIndexPath(Path *path);
static Path * CreateColumnarSeqScanPath(PlannerInfo *root, RelOptInfo *rel,
Oid relationId);
static void RecostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId);
static void RecostColumnarIndexPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
IndexPath *indexPath); IndexPath *indexPath);
static Cost ColumnarIndexScanAddStartupCost(RelOptInfo *rel, Oid relationId,
IndexPath *indexPath);
static Cost ColumnarIndexScanAddTotalCost(PlannerInfo *root, RelOptInfo *rel,
Oid relationId, IndexPath *indexPath);
static void CostColumnarSeqPath(RelOptInfo *rel, Oid relationId, Path *path); static void CostColumnarSeqPath(RelOptInfo *rel, Oid relationId, Path *path);
static int RelationIdGetNumberOfAttributes(Oid relationId); static void CostColumnarScan(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
CustomPath *cpath, int numberOfColumnsRead,
int nClauses);
/* functions to add new paths */
static void AddColumnarScanPaths(PlannerInfo *root, RelOptInfo *rel, static void AddColumnarScanPaths(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte); RangeTblEntry *rte);
static void AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte, Relids required_relids);
/* helper functions to be used when costing paths or altering them */
static void RemovePathsByPredicate(RelOptInfo *rel, PathPredicate removePathPredicate);
static bool IsNotIndexPath(Path *path);
static Cost ColumnarIndexScanAdditionalCost(PlannerInfo *root, RelOptInfo *rel,
Oid relationId, IndexPath *indexPath);
static int RelationIdGetNumberOfAttributes(Oid relationId);
static Cost ColumnarPerStripeScanCost(RelOptInfo *rel, Oid relationId,
int numberOfColumnsRead);
static uint64 ColumnarTableStripeCount(Oid relationId);
static Path * CreateColumnarSeqScanPath(PlannerInfo *root, RelOptInfo *rel,
Oid relationId);
static void AddColumnarScanPathsRec(PlannerInfo *root, RelOptInfo *rel, static void AddColumnarScanPathsRec(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte, Relids paramRelids, RangeTblEntry *rte, Relids paramRelids,
Relids candidateRelids, Relids candidateRelids,
int depthLimit); int depthLimit);
static void AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel,
RangeTblEntry *rte, Relids required_relids); /* hooks and callbacks */
static void CostColumnarScan(CustomPath *cpath, PlannerInfo *root, static void ColumnarSetRelPathlistHook(PlannerInfo *root, RelOptInfo *rel, Index rti,
RelOptInfo *rel, Oid relationId, RangeTblEntry *rte);
int numberOfColumnsRead, int nClauses);
static Cost ColumnarPerStripeScanCost(RelOptInfo *rel, Oid relationId,
int numberOfColumnsRead);
static uint64 ColumnarTableStripeCount(Oid relationId);
static Plan * ColumnarScanPath_PlanCustomPath(PlannerInfo *root, static Plan * ColumnarScanPath_PlanCustomPath(PlannerInfo *root,
RelOptInfo *rel, RelOptInfo *rel,
struct CustomPath *best_path, struct CustomPath *best_path,
List *tlist, List *tlist,
List *clauses, List *clauses,
List *custom_plans); List *custom_plans);
static Node * ColumnarScan_CreateCustomScanState(CustomScan *cscan); static Node * ColumnarScan_CreateCustomScanState(CustomScan *cscan);
static void ColumnarScan_BeginCustomScan(CustomScanState *node, EState *estate, static void ColumnarScan_BeginCustomScan(CustomScanState *node, EState *estate,
@ -106,17 +110,20 @@ static void ColumnarScan_EndCustomScan(CustomScanState *node);
static void ColumnarScan_ReScanCustomScan(CustomScanState *node); static void ColumnarScan_ReScanCustomScan(CustomScanState *node);
static void ColumnarScan_ExplainCustomScan(CustomScanState *node, List *ancestors, static void ColumnarScan_ExplainCustomScan(CustomScanState *node, List *ancestors,
ExplainState *es); ExplainState *es);
/* helper functions to build strings for EXPLAIN */
static const char * ColumnarPushdownClausesStr(List *context, List *clauses); static const char * ColumnarPushdownClausesStr(List *context, List *clauses);
static const char * ColumnarProjectedColumnsStr(List *context, static const char * ColumnarProjectedColumnsStr(List *context,
List *projectedColumns); List *projectedColumns);
static List * ColumnarVarNeeded(ColumnarScanState *columnarScanState);
static Bitmapset * ColumnarAttrNeeded(ScanState *ss);
#if PG_VERSION_NUM >= 130000 #if PG_VERSION_NUM >= 130000
static List * set_deparse_context_planstate(List *dpcontext, Node *node, static List * set_deparse_context_planstate(List *dpcontext, Node *node,
List *ancestors); List *ancestors);
#endif #endif
/* other helpers */
static List * ColumnarVarNeeded(ColumnarScanState *columnarScanState);
static Bitmapset * ColumnarAttrNeeded(ScanState *ss);
/* saved hook value in case of unload */ /* saved hook value in case of unload */
static set_rel_pathlist_hook_type PreviousSetRelPathlistHook = NULL; static set_rel_pathlist_hook_type PreviousSetRelPathlistHook = NULL;
@ -281,7 +288,7 @@ ColumnarSetRelPathlistHook(PlannerInfo *root, RelOptInfo *rel, Index rti,
* Before doing that, we first re-cost all the existing paths so that * Before doing that, we first re-cost all the existing paths so that
* add_path makes correct cost comparisons when appending our SeqPath. * add_path makes correct cost comparisons when appending our SeqPath.
*/ */
RecostColumnarPaths(root, rel, rte->relid); CostColumnarPaths(root, rel, rte->relid);
Path *seqPath = CreateColumnarSeqScanPath(root, rel, rte->relid); Path *seqPath = CreateColumnarSeqScanPath(root, rel, rte->relid);
add_path(rel, seqPath); add_path(rel, seqPath);
@ -361,11 +368,11 @@ CreateColumnarSeqScanPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId)
/* /*
* RecostColumnarPaths re-costs paths of given RelOptInfo for * CostColumnarPaths re-costs paths of given RelOptInfo for
* columnar table with relationId. * columnar table with relationId.
*/ */
static void static void
RecostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId) CostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId)
{ {
Path *path = NULL; Path *path = NULL;
foreach_ptr(path, rel->pathlist) foreach_ptr(path, rel->pathlist)
@ -379,7 +386,7 @@ RecostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId)
* TableAmRoutine). For this reason, we only consider IndexPath's * TableAmRoutine). For this reason, we only consider IndexPath's
* here. * here.
*/ */
RecostColumnarIndexPath(root, rel, relationId, (IndexPath *) path); CostColumnarIndexPath(root, rel, relationId, (IndexPath *) path);
} }
else if (path->pathtype == T_SeqScan) else if (path->pathtype == T_SeqScan)
{ {
@ -390,11 +397,11 @@ RecostColumnarPaths(PlannerInfo *root, RelOptInfo *rel, Oid relationId)
/* /*
* RecostColumnarIndexPath re-costs given index path for columnar table with * CostColumnarIndexPath re-costs given index path for columnar table with
* relationId. * relationId.
*/ */
static void static void
RecostColumnarIndexPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId, CostColumnarIndexPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
IndexPath *indexPath) IndexPath *indexPath)
{ {
if (!enable_indexscan) if (!enable_indexscan)
@ -410,21 +417,12 @@ RecostColumnarIndexPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
/* /*
* We estimate the cost for columnar table read during index scan. Also, * We estimate the cost for columnar table read during index scan. Also,
* instead of overwriting startup & total costs, we "add" ours to the * instead of overwriting total cost, we "add" ours to the cost estimated
* costs estimated by indexAM since we should consider index traversal * by indexAM since we should consider index traversal related costs too.
* related costs too.
*/ */
Cost indexAMStartupCost = indexPath->path.startup_cost; Cost columnarIndexScanCost = ColumnarIndexScanAdditionalCost(root, rel, relationId,
Cost indexAMScanCost = indexPath->path.total_cost - indexAMStartupCost;
Cost columnarIndexScanStartupCost = ColumnarIndexScanAddStartupCost(rel, relationId,
indexPath); indexPath);
Cost columnarIndexScanCost = ColumnarIndexScanAddTotalCost(root, rel, relationId, indexPath->path.total_cost += columnarIndexScanCost;
indexPath);
indexPath->path.startup_cost = indexAMStartupCost + columnarIndexScanStartupCost;
indexPath->path.total_cost = indexPath->path.startup_cost +
indexAMScanCost + columnarIndexScanCost;
ereport(DEBUG4, (errmsg("columnar table index scan costs re-estimated " ereport(DEBUG4, (errmsg("columnar table index scan costs re-estimated "
"by columnarAM (including indexAM costs): " "by columnarAM (including indexAM costs): "
@ -435,25 +433,11 @@ RecostColumnarIndexPath(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
/* /*
* ColumnarIndexScanAddStartupCost returns additional startup cost estimated * ColumnarIndexScanAdditionalCost returns additional cost estimated for
* for index scan described by IndexPath for columnar table with relationId.
*/
static Cost
ColumnarIndexScanAddStartupCost(RelOptInfo *rel, Oid relationId, IndexPath *indexPath)
{
int numberOfColumnsRead = RelationIdGetNumberOfAttributes(relationId);
/* we would at least read one stripe */
return ColumnarPerStripeScanCost(rel, relationId, numberOfColumnsRead);
}
/*
* ColumnarIndexScanAddTotalCost returns additional cost estimated for
* index scan described by IndexPath for columnar table with relationId. * index scan described by IndexPath for columnar table with relationId.
*/ */
static Cost static Cost
ColumnarIndexScanAddTotalCost(PlannerInfo *root, RelOptInfo *rel, ColumnarIndexScanAdditionalCost(PlannerInfo *root, RelOptInfo *rel,
Oid relationId, IndexPath *indexPath) Oid relationId, IndexPath *indexPath)
{ {
int numberOfColumnsRead = RelationIdGetNumberOfAttributes(relationId); int numberOfColumnsRead = RelationIdGetNumberOfAttributes(relationId);
@ -519,6 +503,9 @@ ColumnarIndexScanAddTotalCost(PlannerInfo *root, RelOptInfo *rel,
minStripeReadCount + complementIndexCorrelation * (maxStripeReadCount - minStripeReadCount + complementIndexCorrelation * (maxStripeReadCount -
minStripeReadCount); minStripeReadCount);
/* even in the best case, we will read a single stripe */
estimatedStripeReadCount = Max(estimatedStripeReadCount, 1.0);
Cost scanCost = perStripeCost * estimatedStripeReadCount; Cost scanCost = perStripeCost * estimatedStripeReadCount;
ereport(DEBUG4, (errmsg("re-costing index scan for columnar table: " ereport(DEBUG4, (errmsg("re-costing index scan for columnar table: "
@ -1132,7 +1119,7 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte,
int numberOfColumnsRead = bms_num_members(rte->selectedCols); int numberOfColumnsRead = bms_num_members(rte->selectedCols);
int numberOfClausesPushed = list_length(cpath->custom_private); int numberOfClausesPushed = list_length(cpath->custom_private);
CostColumnarScan(cpath, root, rel, rte->relid, numberOfColumnsRead, CostColumnarScan(root, rel, rte->relid, cpath, numberOfColumnsRead,
numberOfClausesPushed); numberOfClausesPushed);
@ -1155,8 +1142,8 @@ AddColumnarScanPath(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte,
* columns to read how many pages need to be read. * columns to read how many pages need to be read.
*/ */
static void static void
CostColumnarScan(CustomPath *cpath, PlannerInfo *root, RelOptInfo *rel, CostColumnarScan(PlannerInfo *root, RelOptInfo *rel, Oid relationId,
Oid relationId, int numberOfColumnsRead, int nClauses) CustomPath *cpath, int numberOfColumnsRead, int nClauses)
{ {
Path *path = &cpath->path; Path *path = &cpath->path;

View File

@ -401,12 +401,12 @@ $$
t t
(1 row) (1 row)
SELECT columnar_test_helpers.uses_custom_scan ( SELECT columnar_test_helpers.uses_index_scan (
$$ $$
SELECT a FROM full_correlated WHERE a=1000; SELECT a FROM full_correlated WHERE a=1000;
$$ $$
); );
uses_custom_scan uses_index_scan
--------------------------------------------------------------------- ---------------------------------------------------------------------
t t
(1 row) (1 row)

View File

@ -223,7 +223,7 @@ SELECT a FROM full_correlated WHERE a=0 OR a=5;
$$ $$
); );
SELECT columnar_test_helpers.uses_custom_scan ( SELECT columnar_test_helpers.uses_index_scan (
$$ $$
SELECT a FROM full_correlated WHERE a=1000; SELECT a FROM full_correlated WHERE a=1000;
$$ $$