diff options
| author | David Rowley | 2021-04-08 11:51:22 +0000 |
|---|---|---|
| committer | David Rowley | 2021-04-08 11:51:22 +0000 |
| commit | 50e17ad281b8d1c1b410c9833955bc80fbad4078 (patch) | |
| tree | faf07e47e95ceade572aaf2afdca08bc35ed69e7 /src/include | |
| parent | 1d257577e08d3e598011d6850fd1025858de8c8c (diff) | |
Speedup ScalarArrayOpExpr evaluation
ScalarArrayOpExprs with "useOr=true" and a set of Consts on the righthand
side have traditionally been evaluated by using a linear search over the
array. When these arrays contain large numbers of elements then this
linear search could become a significant part of execution time.
Here we add a new method of evaluating ScalarArrayOpExpr expressions to
allow them to be evaluated by first building a hash table containing each
element, then on subsequent evaluations, we just probe that hash table to
determine if there is a match.
The planner is in charge of determining when this optimization is possible
and it enables it by setting hashfuncid in the ScalarArrayOpExpr. The
executor will only perform the hash table evaluation when the hashfuncid
is set.
This means that not all cases are optimized. For example CHECK constraints
containing an IN clause won't go through the planner, so won't get the
hashfuncid set. We could maybe do something about that at some later
date. The reason we're not doing it now is from fear that we may slow
down cases where the expression is evaluated only once. Those cases can
be common, for example, a single row INSERT to a table with a CHECK
constraint containing an IN clause.
In the planner, we enable this when there are suitable hash functions for
the ScalarArrayOpExpr's operator and only when there is at least
MIN_ARRAY_SIZE_FOR_HASHED_SAOP elements in the array. The threshold is
currently set to 9.
Author: James Coleman, David Rowley
Reviewed-by: David Rowley, Tomas Vondra, Heikki Linnakangas
Discussion: https://postgr.es/m/CAAaqYe8x62+=wn0zvNKCj55tPpg-JBHzhZFFc6ANovdqFw7-dA@mail.gmail.com
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
| -rw-r--r-- | src/include/executor/execExpr.h | 19 | ||||
| -rw-r--r-- | src/include/nodes/primnodes.h | 9 | ||||
| -rw-r--r-- | src/include/optimizer/optimizer.h | 2 |
4 files changed, 30 insertions, 2 deletions
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index abd4bffff5f..45722fdbb13 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202104072 +#define CATALOG_VERSION_NO 202104081 #endif diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 1b7f9865b0a..2449cde7ad3 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -20,6 +20,7 @@ /* forward references to avoid circularity */ struct ExprEvalStep; struct SubscriptingRefState; +struct ScalarArrayOpExprHashTable; /* Bits in ExprState->flags (see also execnodes.h for public flag bits): */ /* expression's interpreter has been initialized */ @@ -218,6 +219,7 @@ typedef enum ExprEvalOp /* evaluate assorted special-purpose expression types */ EEOP_CONVERT_ROWTYPE, EEOP_SCALARARRAYOP, + EEOP_HASHED_SCALARARRAYOP, EEOP_XMLEXPR, EEOP_AGGREF, EEOP_GROUPING_FUNC, @@ -554,6 +556,21 @@ typedef struct ExprEvalStep PGFunction fn_addr; /* actual call address */ } scalararrayop; + /* for EEOP_HASHED_SCALARARRAYOP */ + struct + { + bool has_nulls; + struct ScalarArrayOpExprHashTable *elements_tab; + FmgrInfo *finfo; /* function's lookup data */ + FunctionCallInfo fcinfo_data; /* arguments etc */ + /* faster to access without additional indirection: */ + PGFunction fn_addr; /* actual call address */ + FmgrInfo *hash_finfo; /* function's lookup data */ + FunctionCallInfo hash_fcinfo_data; /* arguments etc */ + /* faster to access without additional indirection: */ + PGFunction hash_fn_addr; /* actual call address */ + } hashedscalararrayop; + /* for EEOP_XMLEXPR */ struct { @@ -725,6 +742,8 @@ extern void ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, extern void ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext); extern void ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op); +extern void ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, + ExprContext *econtext); extern void ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op); extern void ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op); extern void ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op); diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index f2ac4e51f16..9ae851d8477 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -578,12 +578,19 @@ typedef OpExpr NullIfExpr; * is almost the same as for the underlying operator, but we need a useOr * flag to remember whether it's ANY or ALL, and we don't have to store * the result type (or the collation) because it must be boolean. + * + * A ScalarArrayOpExpr with a valid hashfuncid is evaluated during execution + * by building a hash table containing the Const values from the rhs arg. + * This table is probed during expression evaluation. Only useOr=true + * ScalarArrayOpExpr with Const arrays on the rhs can have the hashfuncid + * field set. See convert_saop_to_hashed_saop(). */ typedef struct ScalarArrayOpExpr { Expr xpr; Oid opno; /* PG_OPERATOR OID of the operator */ - Oid opfuncid; /* PG_PROC OID of underlying function */ + Oid opfuncid; /* PG_PROC OID of comparison function */ + Oid hashfuncid; /* PG_PROC OID of hash func or InvalidOid */ bool useOr; /* true for ANY, false for ALL */ Oid inputcollid; /* OID of collation that operator should use */ List *args; /* the scalar and array operands */ diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index d587952b7d6..68ebb84bf5d 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -146,6 +146,8 @@ extern bool contain_volatile_functions_not_nextval(Node *clause); extern Node *eval_const_expressions(PlannerInfo *root, Node *node); +extern void convert_saop_to_hashed_saop(Node *node); + extern Node *estimate_expression_value(PlannerInfo *root, Node *node); extern Expr *evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, |
