forked from huawei/openGauss-server
增加join行数估算时候对类型转换函数的支持
This commit is contained in:
parent
ee30a37bb3
commit
e642f9d5f8
|
|
@ -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|
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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) \
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue