增加join行数估算时候对类型转换函数的支持

This commit is contained in:
luozihao 2021-12-23 11:59:06 +08:00
parent ee30a37bb3
commit e642f9d5f8
9 changed files with 597 additions and 14 deletions

View File

@ -653,7 +653,7 @@ enable_auto_explain|bool|0,0|NULL|NULL|
auto_explain_level|enum|off,log,notice|NULL|NULL|
cost_weight_index|real|1e-10,1e+10|NULL|NULL|
default_limit_rows|real|-100,1.79769e+308|NULL|NULL|
sql_beta_feature|enum|sel_semi_poisson,sel_expr_instr,param_path_gen,rand_cost_opt,param_path_opt,page_est_opt,none|NULL|NULL|
sql_beta_feature|enum|join_sel_with_cast_func,no_unique_index_first,sel_semi_poisson,sel_expr_instr,param_path_gen,rand_cost_opt,param_path_opt,page_est_opt,none|NULL|NULL|
xlog_idle_flushes_before_sleep|int64|0,576460752303423487|NULL|NULL|
wal_writer_cpu|int|-1,2147483647|NULL|NULL|
wal_file_init_num|int|1,2147483647|NULL|NULL|

View File

@ -38,7 +38,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \
tsquery_op.o tsquery_rewrite.o tsquery_util.o tsrank.o \
tsvector.o tsvector_op.o tsvector_parser.o \
txid.o uuid.o windowfuncs.o xml.o extended_statistics.o clientlogic_bytea.o clientlogicsettings.o \
median_aggs.o
median_aggs.o expr_distinct.o
like.o: like.cpp like_match.cpp

View File

@ -0,0 +1,434 @@
/* -------------------------------------------------------------------------
*
* expr_distinct.cpp
* utility functions for get number of distinct of expressions
*
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2021. All rights reserved.
*
* IDENTIFICATION
* src/backend/utils/adt/expr_distinct.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include "access/transam.h"
#include "access/sysattr.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
#include "nodes/nodes.h"
#include "optimizer/cost.h"
#include "optimizer/optimizerdebug.h"
#include "optimizer/pathnode.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/streamplan.h"
#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
#include "parser/parse_relation.h"
#include "storage/buf/bufmgr.h"
#include "storage/proc.h"
#include "utils/dynahash.h"
#include "utils/expr_distinct.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/selfuncs.h"
#include "utils/syscache.h"
/*
* Context for estimate number of distinct of function
*/
typedef struct {
double numDistinct[2]; /* numdistinct of the var */
Oid attType; /* attType of current values */
int numMcv; /* original number of MCV values in stats */
int numHisBounds; /* original number of histogram bounds in stats */
/* following data may change during runtime */
int numFMcv; /* length of array mcvValues, may be changed at runtime */
int numFHisBounds; /* length of array hisValues, simliar to mcvValues */
Datum *fMcv; /* "MCV" values or f(..(MCV)), except NULL */
Datum *fHisBounds; /* "histogram bounds" or f(..g(histogram bounds)), except NULL */
bool needAdjust; /* whether var distinct need adjust */
} EstiFuncDistinctContext;
static char *GetFunctionNameWithDefault(Oid fnOid);
static void EstimateExprNumDistinct(PlannerInfo *root, VariableStatData *varData, Node *node, bool isJoinVar,
bool *isDefault);
static void GetNumDistinctFuncExpr(PlannerInfo *root, VariableStatData *varData, FuncExpr *funcExpr, bool isJoinVar);
static void GetExprNumDistinctWalker(PlannerInfo *root, VariableStatData *varData, Node *node, bool isJoinVar);
static void TransferFunctionNumDistinct(PlannerInfo *root, VariableStatData *varData, FuncExpr *funcExpr,
bool isJoinVar);
static bool CheckFuncArgsForTransferNumDistinct(FuncExpr *funcExpr, Node **varNode);
static bool IsFunctionTransferNumDistinct(FuncExpr *funcExpr);
/*
* The array collects all of the type-cast functions which can transfer number of distinct from any one of
* its arguments, other parameters are viewed as Const.
*/
static Oid g_typeCastFuncOids[] = {
/* type cast from bool */
BOOLTOINT1FUNCOID, BOOLTOINT2FUNCOID, BOOLTOINT4FUNCOID, BOOLTOINT8FUNCOID, BOOLTOTEXTFUNCOID,
/* type cast from int1 */
I1TOI2FUNCOID, I1TOI4FUNCOID, I1TOI8FUNCOID, I1TOF4FUNCOID, I1TOF8FUNCOID, INT1TOBPCHARFUNCOID,
INT1TOVARCHARFUNCOID, INT1TONVARCHAR2FUNCOID, INT1TOTEXTFUNCOID, INT1TONUMERICFUNCOID, INT1TOINTERVALFUNCOID,
/* type cast from int2 */
I2TOI1FUNCOID, INT2TOINT4FUNCOID, INT2TOFLOAT4FUNCOID, INT2TOFLOAT8FUNCOID, INT2TOBPCHAR, INT2TOTEXTFUNCOID,
INT2TOVARCHARFUNCOID, INT2TOINT8FUNCOID, INT2TONUMERICFUNCOID, INT2TOINTERVALFUNCOID,
/* type cast from int4 */
I4TOI1FUNCOID, INT4TOINT2FUNCOID, INT4TOINT8FUNCOID, INT4TOFLOAT8FUNCOID, INTEGER2CASHFUNCOID,
INT4TONUMERICFUNCOID, INT4TOINTERVALFUNCOID, INT4TOHEXFUNCOID, INT4TOBPCHARFUNCOID, INT4TOTEXTFUNCOID,
INT4TOVARCHARFUNCOID, INT4TOCHARFUNCOID, INT4TOCHRFUNCOID,
/* type cast from int8 */
I8TOI1FUNCOID, INT8TOINT2FUNCOID, INT8TOINT4FUNCOID, INT8TOBPCHARFUNCOID, INT8TOTEXTFUNCOID, INT8TOVARCHARFUNCOID,
INT8TONUMERICFUNCOID, INT8TOHEXFUNCOID,
/* type cast from float4/float8 */
FLOAT4TOBPCHARFUNCOID, FLOAT4TOTEXTFUNCOID, FLOAT4TOVARCHARFUNCOID, FLOAT4TOFLOAT8FUNCOID,
FLOAT4TONUMERICFUNCOID, FLOAT8TOBPCHARFUNCOID, FLOAT8TOINTERVALFUNCOID, FLOAT8TOTEXTFUNCOID,
FLOAT8TOVARCHARFUNCOID, FLOAT8TONUMERICFUNCOID, FLOAT8TOTIMESTAMPFUNCOID,
/* type cast from numeric */
NUMERICTOBPCHARFUNCOID, NUMERICTOTEXTFUNCOID, NUMERICTOVARCHARFUNCOID,
/* type cast from timestamp/date/time */
DEFAULTFORMATTIMESTAMP2CHARFUNCOID, DEFAULTFORMATTIMESTAMPTZ2CHARFUNCOID, TIMESATMPTOTEXTFUNCOID,
TIMESTAMPTOVARCHARFUNCOID, TIMESTAMP2TIMESTAMPTZFUNCOID, TIMESTAMPTZ2TIMESTAMPFUNCOID,
DATETIMESTAMPTZFUNCOID, DATETOTIMESTAMPFUNCOID, DATETOBPCHARFUNCOID, DATETOVARCHARFUNCOID, DATETOTEXTFUNCOID,
DATEANDTIMETOTIMESTAMPFUNCOID, DTAETIME2TIMESTAMPTZFUNCOID, TIMETOINTERVALFUNCOID, TIMESTAMPZONETOTEXTFUNCOID,
TIME2TIMETZFUNCOID, RELTIMETOINTERVALFUNCOID,
/* type cast from text */
TODATEDEFAULTFUNCOID, TODATEFUNCOID, TOTIMESTAMPFUNCOID, TOTIMESTAMPDEFAULTFUNCOID,
TEXTTOREGCLASSFUNCOID, TEXTTOINT1FUNCOID, TEXTTOINT2FUNCOID, TEXTTOINT4FUNCOID, TEXTTOINT8FUNCOID,
TEXTTONUMERICFUNCOID, TEXTTOTIMESTAMP, TIMESTAMPTONEWTIMEZONEFUNCOID, TIMESTAMPTZTONEWTIMEZONEFUNCOID,
HEXTORAWFUNCOID,
/* type cast from char/varchar/bpchar */
VARCHARTONUMERICFUNCOID, VARCHARTOINT4FUNCOID, VARCHARTOINT8FUNCOID, VARCHARTOTIMESTAMPFUNCOID,
BPCHARTOINT4FUNCOID, BPCHARTOINT8FUNCOID, BPCHARTONUMERICFUNCOID, BPCHARTOTIMESTAMPFUNCOID,
RTRIM1FUNCOID, BPCHARTEXTFUNCOID, CHARTOBPCHARFUNCOID, CHARTOTEXTFUNCOID
};
static char *GetFunctionNameWithDefault(Oid fnOid)
{
char *funcName = get_func_name(fnOid);
if (funcName == NULL) {
funcName = "unknown-name";
}
return funcName;
}
/*
* Entrance of the distinct estimation for expr whose stats is unavailable
*
* Handle expr-case in get_variable_numdistinct, aim to estimate variable distinct if no stats
* (for the variable) are available. Also, GUC 'cost_model_version' controls the behaviour of
* the router.
*
* Note:
* - function get_variable_numdistinct and get_variable_numdistinct_router should be called
* after examine_variable, otherwise, it may fail to get stats which actually exists.
* - This function may fail to estimate expr distinct, returns 0.0 (means unknown).
* - adjust ratio will be applied to the raw distinct if needAdjust is true, and
* varData->needAdjust is used to transfer the indicators.
*/
double GetExprNumDistinctRouter(VariableStatData *varData, bool needAdjust, STATS_EST_TYPE eType, bool isJoinVar)
{
double distinct = 0.0;
int idx = 0;
bool saveNeedAdjust = varData->needAdjust;
varData->needAdjust = needAdjust;
ereport(DEBUG2, (errmodule(MOD_OPT), errmsg(
"[Get Expr NumDistinct Router]: -------- <START>: adjust: %s --------", needAdjust ? "true" : "false")));
if (IS_PGXC_COORDINATOR && (eType == STATS_TYPE_LOCAL)) {
/* for local distinct */
idx = 0;
} else {
/* for global distinct */
idx = 1;
}
if (varData->numDistinct[idx] > 0.0) {
distinct = clamp_row_est(varData->numDistinct[idx]);
} else if (!varData->isEstimated) {
GetExprNumDistinctWalker(varData->root, varData, varData->var, isJoinVar);
varData->isEstimated = true;
if (varData->numDistinct[idx] > 0.0) {
distinct = clamp_row_est(varData->numDistinct[idx]);
}
}
varData->needAdjust = saveNeedAdjust;
ereport(DEBUG2, (errmodule(MOD_OPT),
errmsg("[Get Expr NumDistinct Router]: -------- <END>: distinct: %.0lf --------", distinct)));
return distinct;
}
/*
* implementation of GetExprNumDistinctRouter with "cost_model_version = 1"
*
* NB: parameters node may be varData->var or other form or sub-node of varData->var
*/
static void GetExprNumDistinctWalker(PlannerInfo *root, VariableStatData *varData, Node *node, bool isJoinVar)
{
char *exprName = NULL;
errno_t rc =
memset_s(varData->numDistinct, sizeof(varData->numDistinct[0]) * 2, 0, sizeof(varData->numDistinct[0]) * 2);
securec_check(rc, "\0", "\0");
switch (nodeTag(node)) {
case T_FuncExpr:
exprName = "FuncExpr";
GetNumDistinctFuncExpr(root, varData, (FuncExpr *)node, isJoinVar);
break;
default:
exprName = "Unknown-Expr";
break;
}
ereport(DEBUG2,
(errmodule(MOD_OPT),
(errmsg("[%s Distinct Estimation]: local distinct is %.0lf, global distinct is %.0lf",
exprName, varData->numDistinct[0], varData->numDistinct[1]))));
}
/*
* Estimate the number of distinct of function expression.
*
* Parameters:
* @in funcExpr: the function expression to calculate distinct value
* @in isJoinVar: is the node used for join?
*
* @out: vardata: set the distinct value on numdistinct.
*/
static void GetNumDistinctFuncExpr(PlannerInfo *root, VariableStatData *varData, FuncExpr *funcExpr, bool isJoinVar)
{
if (funcExpr->funcid >= FirstNormalObjectId) {
/* user-defined function, do nothing */
return;
}
/*
* Let p denotes function can transfer distinct, f all other functions, w type-cast functions
* which can also transfer distinct. In general, p contains w. Then all possible cases are:
* 1. p(p(p(..p(var)))): p include w,
* transfer distinct of var to top level
* 2. p(p(p(..p(f(var))))): p include w,
* transfer distinct of f to top level, distinct of f is estimated from var
* 3. f(var):
* estimate distinct of f from var
* 4. f(w(..w(var))
* estimate distinct of f from var
* 5. ..f(..(p(..))): p except w
* can not estimate, return unknown
* 6. ..f(..(f(..))):
* can not estimate, return unknown
*/
/* bool-return function */
if (get_func_rettype(funcExpr->funcid) == BOOLOID) {
varData->numDistinct[0] = 2.0;
varData->numDistinct[1] = 2.0;
return;
}
if (funcExpr->args == NULL) {
ereport(DEBUG2,
(errmodule(MOD_OPT),
errmsg("[Func Distinct Estimation]:can not get number of distinct of function oid %u with no argument",
funcExpr->funcid)));
return;
}
/* if failed to transfer, we can not estimate either */
if (IsFunctionTransferNumDistinct(funcExpr)) {
/* transfer the number of distinct */
TransferFunctionNumDistinct(root, varData, funcExpr, isJoinVar);
} else {
/* estimate the number of distinct */
return;
}
}
/*
* Estimate the number of distinct of the specifed node, work for get_num_distinct_coalesce,
* get_num_distinct_casewhen and so on. The estimated numdistinct are always given, stored in
* vardata->numdistinct[2].
*
* Parameters:
* @in varData: the info we need to calculate distinct value, numdistinct is returned in varData
* @in node: the node to calculate distinct value
* @in isJoinVar: is the node used for join?
* @out isDefault: is the numdistinct is a default value ?
*/
static void EstimateExprNumDistinct(PlannerInfo *root, VariableStatData *varData, Node *node, bool isJoinVar,
bool *isDefault)
{
VariableStatData tmpVarData;
SpecialJoinInfo sjInfo;
errno_t rc = EOK;
varData->numDistinct[0] = 0.0;
varData->numDistinct[1] = 0.0;
/* return after count it if it's Const. */
if (IsA(node, Const)) {
varData->numDistinct[0] = 1.0;
varData->numDistinct[1] = 1.0;
*isDefault = false;
return;
}
/* XXX should min_lefthand ? */
rc = memset_s(&sjInfo, sizeof(sjInfo), 0, sizeof(sjInfo));
securec_check(rc, "\0", "\0");
sjInfo.min_lefthand = root->all_baserels;
sjInfo.min_righthand = NULL;
examine_variable(root, node, 0, &tmpVarData);
tmpVarData.needAdjust = varData->needAdjust;
double joinRatio = get_join_ratio(&tmpVarData, &sjInfo);
varData->numDistinct[0] =
get_variable_numdistinct(&tmpVarData, isDefault, tmpVarData.needAdjust, joinRatio, &sjInfo,
STATS_TYPE_LOCAL, isJoinVar);
varData->numDistinct[1] =
get_variable_numdistinct(&tmpVarData, isDefault, tmpVarData.needAdjust, joinRatio, &sjInfo,
STATS_TYPE_GLOBAL, isJoinVar);
ReleaseVariableStats(tmpVarData);
}
/*
* try to transfer number of distinct of given funcExpr, return unknown if fail
*/
static void TransferFunctionNumDistinct(PlannerInfo *root, VariableStatData *varData, FuncExpr *funcExpr,
bool isJoinVar)
{
bool isDefault = false;
Node *varNode = NULL;
/* check arguments and find the var-argument */
if (!CheckFuncArgsForTransferNumDistinct(funcExpr, &varNode)) {
return;
}
/* recursive to the arg, if there is no distinct for the arg, return unknown */
EstimateExprNumDistinct(root, varData, varNode, isJoinVar, &isDefault);
ereport(DEBUG2,
(errmodule(MOD_OPT),
errmsg("[Func Distinct Estimation]: succeed to transfer number of distinct of function oid: %u",
funcExpr->funcid)));
}
/*
* check arguments of the func, return true and var-node if ok. Assume there is only one var or expr(var,..) in
* its arguments. We allow f(var, const), f(const, var), f(expr(var), const) and f(expr(var1, var2), const)
*
* return true if ok, and varNode indicates the location of the Var
*/
static bool CheckFuncArgsForTransferNumDistinct(FuncExpr *funcExpr, Node **varNode)
{
ListCell *listCell = NULL;
int numVars = 0;
Node *lastNode = NULL;
/* find the first "var" */
foreach (listCell, funcExpr->args) {
Node *node = (Node *)lfirst(listCell);
if (IsA(node, Var)) {
numVars++;
lastNode = node;
} else if (IsA(node, Const)) {
continue;
} else {
List *varList =
pull_var_clause(node, PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS, PVC_RECURSE_SPECIAL_EXPR);
if (varList != NULL) {
numVars++;
lastNode = node;
}
}
}
if (numVars == 0) {
*varNode = (Node *)linitial(funcExpr->args);
return true;
} else if (numVars == 1) {
*varNode = lastNode;
return true;
} else {
*varNode = NULL;
ereport(DEBUG2, (errmodule(MOD_OPT),
errmsg("[Check Args for Transfer]: more than one var-arguments for function oid: %u",
funcExpr->funcid)));
return false;
}
}
/*
* check if the function can transfer number of distinct from one of its parameters
*/
static bool IsFunctionTransferNumDistinct(FuncExpr *funcExpr)
{
/*
* We explicitly allow or disallow functions to transfer number of distinct.
*
* If a function called in form of COERCE_EXPLICIT_CAST/COERCE_IMPLICIT_CAST, we can not
* conclude that this function can transfer number of distinct, e.g.
*
* create table t1(price text);
* values: '20.01',
* '20.02',
* '20.12',
* '20.30',
* '20.99',
* '20.88'
* select price from t1 where int1(price) = 20;
* The filter transformed by Optimizer is:
* (((numeric_in(textout(price), 0::oid, (-1)))::tinyint)::bigint = 20)
*
* numeric::tinyint is the function numeric_int1 which is called as COERCE_EXPLICIT_CAST,
* and it will make rounding to ensure an integer is assigned to int1. Hence a explicitly
* cast function may not transfer number of distinct.
*/
Oid funcId = funcExpr->funcid;
char *funcName = GetFunctionNameWithDefault(funcExpr->funcid);
/* special functions whose oid is not built-in, but we can transfer numdistinct for them */
if (strcmp(funcName, "to_text") == 0 || strcmp(funcName, "to_varchar2") == 0 ||
strcmp(funcName, "to_nvarchar2") == 0 || strcmp(funcName, "to_ts") == 0 ||
(strcmp(funcName, "to_number") == 0 && (funcId != TONUMBERFUNCOID))) {
pfree(funcName);
return true;
}
for (int i = 0; i < (int)lengthof(g_typeCastFuncOids); i++) {
if (g_typeCastFuncOids[i] == funcId) {
pfree(funcName);
return true;
}
}
pfree(funcName);
return false;
}

View File

@ -139,6 +139,7 @@
#include "utils/bytea.h"
#include "utils/date.h"
#include "utils/datum.h"
#include "utils/expr_distinct.h"
#include "utils/extended_statistics.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
@ -193,7 +194,7 @@ static Const* string_to_bytea_const(const char* str, size_t str_len);
static List* specialExpr_group_num(PlannerInfo* root, List* nodeList, double* numdistinct, double rows);
static List* add_unique_group_var(
PlannerInfo* root, List* varinfos, Node* var, VariableStatData* vardata, STATS_EST_TYPE eType = STATS_TYPE_LOCAL);
static double get_join_ratio(VariableStatData* vardata, SpecialJoinInfo* sjinfo);
extern double get_join_ratio(VariableStatData* vardata, SpecialJoinInfo* sjinfo);
bool can_use_possion(VariableStatData* vardata, SpecialJoinInfo* sjinfo, double* ratio);
extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
extern List* find_skew_join_distribute_keys(Plan* plan);
@ -2275,9 +2276,9 @@ static double eqjoinsel_inner(
double relfrac1 = 1.0, relfrac2 = 1.0, relfrac;
nd1 = get_variable_numdistinct(
vardata1, &isdefault1, true, get_join_ratio(vardata1, sjinfo), sjinfo, STATS_TYPE_GLOBAL);
vardata1, &isdefault1, true, get_join_ratio(vardata1, sjinfo), sjinfo, STATS_TYPE_GLOBAL, true);
nd2 = get_variable_numdistinct(
vardata2, &isdefault2, true, get_join_ratio(vardata2, sjinfo), sjinfo, STATS_TYPE_GLOBAL);
vardata2, &isdefault2, true, get_join_ratio(vardata2, sjinfo), sjinfo, STATS_TYPE_GLOBAL, true);
opfuncoid = get_opcode(opera);
if (HeapTupleIsValid(vardata1->statsTuple)) {
@ -2655,9 +2656,9 @@ static double eqjoinsel_semi(
Oid opfuncoid = OidIsValid(opera) ? get_opcode(opera) : InvalidOid;
nd1 = get_variable_numdistinct(
vardata1, &isdefault1, true, get_join_ratio(vardata1, sjinfo), sjinfo, STATS_TYPE_GLOBAL);
vardata1, &isdefault1, true, get_join_ratio(vardata1, sjinfo), sjinfo, STATS_TYPE_GLOBAL, true);
nd2 = get_variable_numdistinct(
vardata2, &isdefault2, true, get_join_ratio(vardata2, sjinfo), sjinfo, STATS_TYPE_GLOBAL);
vardata2, &isdefault2, true, get_join_ratio(vardata2, sjinfo), sjinfo, STATS_TYPE_GLOBAL, true);
/*
* We clamp nd2 to be not more than what we estimate the inner relation's
* size to be. This is intuitively somewhat reasonable since obviously
@ -2861,9 +2862,9 @@ static double neqjoinsel_semi(
nullfrac1 = stats1 ? stats1->stanullfrac : 0.0;
nd1 = get_variable_numdistinct(
vardata1, &isdefault1, true, get_join_ratio(vardata1, sjinfo), sjinfo, STATS_TYPE_GLOBAL);
vardata1, &isdefault1, true, get_join_ratio(vardata1, sjinfo), sjinfo, STATS_TYPE_GLOBAL, true);
nd2 = get_variable_numdistinct(
vardata2, &isdefault2, true, get_join_ratio(vardata2, sjinfo), sjinfo, STATS_TYPE_GLOBAL);
vardata2, &isdefault2, true, get_join_ratio(vardata2, sjinfo), sjinfo, STATS_TYPE_GLOBAL, true);
/*
* When one of the sides contains zero distinct values, the selectivity is zero;
@ -4550,6 +4551,8 @@ void examine_variable(PlannerInfo* root, Node* node, int varRelid, VariableStatD
errno_t rc = memset_s(vardata, sizeof(VariableStatData), 0, sizeof(VariableStatData));
securec_check(rc, "\0", "\0");
vardata->root = root;
/* we enable possion to estimate distinct for default. */
vardata->enablePossion = true;
/* Save the exposed type of the expression */
@ -4980,7 +4983,7 @@ statistic_proc_security_check(const VariableStatData *vardata, Oid func_oid)
* compare the result to exact integer counts, or might divide by it.
*/
double get_variable_numdistinct(VariableStatData* vardata, bool* isdefault, bool adjust_rows, double join_ratio,
SpecialJoinInfo* sjinfo, STATS_EST_TYPE eType)
SpecialJoinInfo* sjinfo, STATS_EST_TYPE eType, bool isJoinVar)
{
double stadistinct;
double stanullfrac = 0.0;
@ -5067,6 +5070,19 @@ double get_variable_numdistinct(VariableStatData* vardata, bool* isdefault, bool
if (vardata->isunique)
stadistinct = -1.0 * (1.0 - stanullfrac);
/*
* If no stats, try to get the estimation
*/
if (ENABLE_SQL_BETA_FEATURE(JOIN_SEL_WITH_CAST_FUNC) && !HeapTupleIsValid(vardata->statsTuple) &&
stadistinct == 0.0) {
stadistinct = GetExprNumDistinctRouter(vardata, adjust_rows, eType, isJoinVar);
if (stadistinct > 0.0) {
ereport(DEBUG2, (errmodule(MOD_OPT),
errmsg("[Get Variable Distinct]: direct distinct is %.0lf by router, early return", stadistinct)));
return clamp_row_est(stadistinct);
}
}
/*
* Otherwise we need to get the relation size; punt if not available.
*/
@ -8697,7 +8713,7 @@ void set_varratio_after_calc_selectivity(
* Return:
* minimum join ratio with specific relation
*/
static double get_join_ratio(VariableStatData* vardata, SpecialJoinInfo* sjinfo)
double get_join_ratio(VariableStatData* vardata, SpecialJoinInfo* sjinfo)
{
double ratio = 1.0;
ListCell* lc = NULL;

View File

@ -993,6 +993,8 @@ static const struct config_enum_entry sql_beta_options[] = {
{"rand_cost_opt", RAND_COST_OPT, false},
{"page_est_opt", PAGE_EST_OPT, false},
{"param_path_opt", PARAM_PATH_OPT, false},
{"no_unique_index_first", NO_UNIQUE_INDEX_FIRST, false},
{"join_sel_with_cast_func", JOIN_SEL_WITH_CAST_FUNC, false},
{NULL, 0, false}
};

View File

@ -168,7 +168,6 @@ typedef FormData_pg_proc *Form_pg_proc;
#define TINTERVALINFUNCOID 246
#define TINTERVALOUTFUNCOID 247
#define TIMENOWFUNCOID 250
#define INT4TOFLOAT8FUNCOID 316
#define BTINT4CMP_OID 351
#define RTRIM1FUNCOID 401
#define NAME2TEXTFUNCOID 406
@ -440,5 +439,99 @@ typedef FormData_pg_proc *Form_pg_proc;
#define OID_REGEXP_SPLIT_TO_TABLE 2765
#define OID_REGEXP_SPLIT_TO_TABLE_NO_FLAG 2766
/* cast functions oid */
#define INT4TOCHARFUNCOID 78
#define INT2TOFLOAT8FUNCOID 235
#define INT2TOFLOAT4FUNCOID 236
#define FLOAT4TOFLOAT8FUNCOID 311
#define INT2TOINT4FUNCOID 313
#define INT4TOINT2FUNCOID 314
#define INT4TOFLOAT8FUNCOID 316
#define BPCHARTEXTFUNCOID 405
#define BOOLTOTEXTFUNCOID 2971
#define BOOLTOINT8FUNCOID 3178
#define BOOLTOINT2FUNCOID 3181
#define INT8TOINT4FUNCOID 480
#define INT4TOINT8FUNCOID 481
#define INT8TOINT2FUNCOID 714
#define INT2TOINT8FUNCOID 754
#define CHARTOBPCHARFUNCOID 860
#define CHARTOTEXTFUNCOID 946
#define FLOAT8TOTIMESTAMPFUNCOID 1158
#define TIMESTAMPTZTONEWTIMEZONEFUNCOID 1159
#define RELTIMETOINTERVALFUNCOID 1177
#define TIMETOINTERVALFUNCOID 1370
#define INT4TOCHRFUNCOID 1621
#define INT4TOHEXFUNCOID 2089
#define INT8TOHEXFUNCOID 2090
#define INT4TONUMERICFUNCOID 1740
#define FLOAT4TONUMERICFUNCOID 1742
#define FLOAT8TONUMERICFUNCOID 1743
#define INT8TONUMERICFUNCOID 1781
#define INT2TONUMERICFUNCOID 1782
#define TEXTTOREGCLASSFUNCOID 1079
#define DATEANDTIMETOTIMESTAMPFUNCOID 2025
#define TIMESTAMPTONEWTIMEZONEFUNCOID 2069
#define TEXTTOTIMESTAMP 4073
#define HEXTORAWFUNCOID 4038
#define DATETOTEXTFUNCOID 4159
#define DATETOBPCHARFUNCOID 4160
#define DATETOVARCHARFUNCOID 4161
#define TIMESTAMPZONETOTEXTFUNCOID 4177
#define TIMESATMPTOTEXTFUNCOID 4178
#define TIMESTAMPTOVARCHARFUNCOID 4179
#define FLOAT8TOINTERVALFUNCOID 4229
#define INT1TONUMERICFUNCOID 5521
#define I1TOI2FUNCOID 5523
#define I2TOI1FUNCOID 5524
#define I1TOI4FUNCOID 5525
#define I4TOI1FUNCOID 5526
#define I1TOI8FUNCOID 5527
#define I8TOI1FUNCOID 5528
#define I1TOF4FUNCOID 5529
#define I1TOF8FUNCOID 5531
#define BOOLTOINT1FUNCOID 5534
#define INT4TOBPCHARFUNCOID 3192
#define DATETOTIMESTAMPFUNCOID 2024
#define BOOLTOINT4FUNCOID 2558
#define INT1TOINTERVALFUNCOID 3189
#define INT2TOINTERVALFUNCOID 3190
#define INT4TOINTERVALFUNCOID 3191
#define INT1TOTEXTFUNCOID 4165
#define INT2TOTEXTFUNCOID 4166
#define INT4TOTEXTFUNCOID 4167
#define INT8TOTEXTFUNCOID 4168
#define FLOAT4TOTEXTFUNCOID 4169
#define FLOAT8TOTEXTFUNCOID 4170
#define NUMERICTOTEXTFUNCOID 4171
#define BPCHARTONUMERICFUNCOID 4172
#define VARCHARTONUMERICFUNCOID 4173
#define VARCHARTOINT4FUNCOID 4174
#define BPCHARTOINT4FUNCOID 4175
#define VARCHARTOINT8FUNCOID 4176
#define INT2TOVARCHARFUNCOID 4180
#define INT4TOVARCHARFUNCOID 4181
#define INT8TOVARCHARFUNCOID 4182
#define NUMERICTOVARCHARFUNCOID 4183
#define FLOAT4TOVARCHARFUNCOID 4184
#define FLOAT8TOVARCHARFUNCOID 4185
#define VARCHARTOTIMESTAMPFUNCOID 4186
#define BPCHARTOTIMESTAMPFUNCOID 4187
#define TEXTTOINT1FUNCOID 4188
#define TEXTTOINT2FUNCOID 4189
#define TEXTTOINT4FUNCOID 4190
#define TEXTTOINT8FUNCOID 4191
#define TEXTTONUMERICFUNCOID 4194
#define BPCHARTOINT8FUNCOID 4195
#define INT1TOVARCHARFUNCOID 4065
#define INT1TONVARCHAR2FUNCOID 4066
#define INT1TOBPCHARFUNCOID 4067
#define INT2TOBPCHAR 4068
#define INT8TOBPCHARFUNCOID 4069
#define FLOAT4TOBPCHARFUNCOID 4070
#define FLOAT8TOBPCHARFUNCOID 4071
#define NUMERICTOBPCHARFUNCOID 4072
#endif /* PG_PROC_H */

View File

@ -0,0 +1,27 @@
/* -------------------------------------------------------------------------
*
* expr_distinct.h
* functions for get number of distinct of expressions.
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Copyright (c) Huawei Technologies Co., Ltd. 2012-2021. All rights reserved.
*
* src/include/utils/expr_distinct.h
*
* -------------------------------------------------------------------------
*/
#ifndef EXPR_DISTINCT_H
#define EXPR_DISTINCT_H
#include "postgres.h"
#include "nodes/relation.h"
#include "utils/selfuncs.h"
#include "utils/be_module.h"
extern double GetExprNumDistinctRouter(VariableStatData *varData, bool needAdjust, STATS_EST_TYPE eType,
bool isJoinVar);
#endif /* EXPR_DISTINCT_H */

View File

@ -356,7 +356,9 @@ typedef enum {
PARAM_PATH_GEN = 4, /* Parametrized Path Generation */
RAND_COST_OPT = 8, /* Optimizing sc_random_page_cost */
PARAM_PATH_OPT = 16, /* Parametrized Path Optimization. */
PAGE_EST_OPT = 32 /* More accurate (rowstored) index pages estimation */
PAGE_EST_OPT = 32, /* More accurate (rowstored) index pages estimation */
NO_UNIQUE_INDEX_FIRST = 64, /* use unique index first rule in path generation */
JOIN_SEL_WITH_CAST_FUNC = 128 /* support cast function while calculating join selectivity */
} sql_beta_param;
#define ENABLE_PRED_PUSH(root) \

View File

@ -100,6 +100,13 @@ typedef struct VariableStatData {
bool isunique; /* matches unique index or DISTINCT clause */
bool enablePossion; /* indentify we can use possion or not */
bool acl_ok; /* result of ACL check on table or column */
PlannerInfo *root; /* Planner info the var reference */
double numDistinct[2]; /* estimated numdistinct, 0: means unknown, [0]: local, [1]: global */
bool isEstimated; /* indicate that whether estimation have already been done */
PlannerInfo *baseRoot; /* Planner info of the baseVar */
Node *baseVar; /* base Var, owner of the statsTuple */
RelOptInfo *baseRel; /* rel of the baseVar */
bool needAdjust; /* true if need adjust on rel */
} VariableStatData;
#define ReleaseVariableStats(vardata) \
@ -129,6 +136,7 @@ typedef struct {
} GroupVarInfo;
extern void set_local_rel_size(PlannerInfo* root, RelOptInfo* rel);
extern double get_join_ratio(VariableStatData* vardata, SpecialJoinInfo* sjinfo);
extern double get_multiple_by_distkey(PlannerInfo* root, List* distkey, double rows);
extern double estimate_agg_num_distinct(PlannerInfo* root, List* group_exprs, Plan* plan, const double* numGroups);
extern double estimate_agg_num_distinct(PlannerInfo* root, List* group_exprs, Path* path, const double* numGroups);
@ -168,7 +176,8 @@ extern bool get_restriction_variable(
extern void get_join_variables(PlannerInfo* root, List* args, SpecialJoinInfo* sjinfo, VariableStatData* vardata1,
VariableStatData* vardata2, bool* join_is_reversed);
extern double get_variable_numdistinct(VariableStatData* vardata, bool* isdefault, bool adjust_rows = true,
double join_ratio = 1.0, SpecialJoinInfo* sjinfo = NULL, STATS_EST_TYPE eType = STATS_TYPE_GLOBAL);
double join_ratio = 1.0, SpecialJoinInfo* sjinfo = NULL, STATS_EST_TYPE eType = STATS_TYPE_GLOBAL,
bool isJoinVar = false);
extern double mcv_selectivity(VariableStatData* vardata, FmgrInfo* opproc, Datum constval, bool varonleft,
double* sumcommonp, Oid equaloperator, bool* inmcv, double* lastcommonp = NULL);
extern double histogram_selectivity(VariableStatData* vardata, FmgrInfo* opproc, Datum constval, bool varonleft,