mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
Use a hash table to speed up NOT IN(values)
Similar to 50e17ad28
, which allowed hash tables to be used for IN clauses
with a set of constants, here we add the same feature for NOT IN clauses.
NOT IN evaluates the same as: WHERE a <> v1 AND a <> v2 AND a <> v3.
Obviously, if we're using a hash table we must be exactly equivalent to
that and return the same result taking into account that either side of
the condition could contain a NULL. This requires a little bit of
special handling to make work with the hash table version.
When processing NOT IN, the ScalarArrayOpExpr's operator will be the <>
operator. To be able to build and lookup a hash table we must use the
<>'s negator operator. The planner checks if that exists and is hashable
and sets the relevant fields in ScalarArrayOpExpr to instruct the executor
to use hashing.
Author: David Rowley, James Coleman
Reviewed-by: James Coleman, Zhihong Yu
Discussion: https://postgr.es/m/CAApHDvoF1mum_FRk6D621edcB6KSHBi2+GAgWmioj5AhOu2vwQ@mail.gmail.com
This commit is contained in:
@ -1205,19 +1205,34 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
AclResult aclresult;
|
||||
FmgrInfo *hash_finfo;
|
||||
FunctionCallInfo hash_fcinfo;
|
||||
Oid cmpfuncid;
|
||||
|
||||
/*
|
||||
* Select the correct comparison function. When we do hashed
|
||||
* NOT IN clauses, the opfuncid will be the inequality
|
||||
* comparison function and negfuncid will be set to equality.
|
||||
* We need to use the equality function for hash probes.
|
||||
*/
|
||||
if (OidIsValid(opexpr->negfuncid))
|
||||
{
|
||||
Assert(OidIsValid(opexpr->hashfuncid));
|
||||
cmpfuncid = opexpr->negfuncid;
|
||||
}
|
||||
else
|
||||
cmpfuncid = opexpr->opfuncid;
|
||||
|
||||
Assert(list_length(opexpr->args) == 2);
|
||||
scalararg = (Expr *) linitial(opexpr->args);
|
||||
arrayarg = (Expr *) lsecond(opexpr->args);
|
||||
|
||||
/* Check permission to call function */
|
||||
aclresult = pg_proc_aclcheck(opexpr->opfuncid,
|
||||
aclresult = pg_proc_aclcheck(cmpfuncid,
|
||||
GetUserId(),
|
||||
ACL_EXECUTE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, OBJECT_FUNCTION,
|
||||
get_func_name(opexpr->opfuncid));
|
||||
InvokeFunctionExecuteHook(opexpr->opfuncid);
|
||||
get_func_name(cmpfuncid));
|
||||
InvokeFunctionExecuteHook(cmpfuncid);
|
||||
|
||||
if (OidIsValid(opexpr->hashfuncid))
|
||||
{
|
||||
@ -1233,7 +1248,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
/* Set up the primary fmgr lookup information */
|
||||
finfo = palloc0(sizeof(FmgrInfo));
|
||||
fcinfo = palloc0(SizeForFunctionCallInfo(2));
|
||||
fmgr_info(opexpr->opfuncid, finfo);
|
||||
fmgr_info(cmpfuncid, finfo);
|
||||
fmgr_info_set_expr((Node *) node, finfo);
|
||||
InitFunctionCallInfoData(*fcinfo, finfo, 2,
|
||||
opexpr->inputcollid, NULL, NULL);
|
||||
@ -1274,6 +1289,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
||||
|
||||
/* And perform the operation */
|
||||
scratch.opcode = EEOP_HASHED_SCALARARRAYOP;
|
||||
scratch.d.hashedscalararrayop.inclause = opexpr->useOr;
|
||||
scratch.d.hashedscalararrayop.finfo = finfo;
|
||||
scratch.d.hashedscalararrayop.fcinfo_data = fcinfo;
|
||||
scratch.d.hashedscalararrayop.fn_addr = finfo->fn_addr;
|
||||
|
Reference in New Issue
Block a user