mirror of https://github.com/citusdata/citus.git
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.cpull/5235/head
parent
cc58b58f73
commit
2b71263e40
|
@ -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);
|
IndexPath *indexPath);
|
||||||
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);
|
|
||||||
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,12 +397,12 @@ 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;
|
indexPath);
|
||||||
|
indexPath->path.total_cost += columnarIndexScanCost;
|
||||||
Cost columnarIndexScanStartupCost = ColumnarIndexScanAddStartupCost(rel, relationId,
|
|
||||||
indexPath);
|
|
||||||
Cost columnarIndexScanCost = ColumnarIndexScanAddTotalCost(root, rel, relationId,
|
|
||||||
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,26 +433,12 @@ 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);
|
||||||
Cost perStripeCost = ColumnarPerStripeScanCost(rel, relationId, numberOfColumnsRead);
|
Cost perStripeCost = ColumnarPerStripeScanCost(rel, relationId, numberOfColumnsRead);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
$$
|
$$
|
||||||
|
|
Loading…
Reference in New Issue