mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +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:
@ -3493,6 +3493,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
|
||||
{
|
||||
ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
|
||||
FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
|
||||
bool inclause = op->d.hashedscalararrayop.inclause;
|
||||
bool strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
|
||||
Datum scalar = fcinfo->args[0].value;
|
||||
bool scalar_isnull = fcinfo->args[0].isnull;
|
||||
@ -3596,7 +3597,12 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
|
||||
/* Check the hash to see if we have a match. */
|
||||
hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar);
|
||||
|
||||
result = BoolGetDatum(hashfound);
|
||||
/* the result depends on if the clause is an IN or NOT IN clause */
|
||||
if (inclause)
|
||||
result = BoolGetDatum(hashfound); /* IN */
|
||||
else
|
||||
result = BoolGetDatum(!hashfound); /* NOT IN */
|
||||
|
||||
resultnull = false;
|
||||
|
||||
/*
|
||||
@ -3605,7 +3611,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
|
||||
* hashtable, but instead marked if we found any when building the table
|
||||
* in has_nulls.
|
||||
*/
|
||||
if (!DatumGetBool(result) && op->d.hashedscalararrayop.has_nulls)
|
||||
if (!hashfound && op->d.hashedscalararrayop.has_nulls)
|
||||
{
|
||||
if (strictfunc)
|
||||
{
|
||||
@ -3633,6 +3639,13 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
|
||||
|
||||
result = op->d.hashedscalararrayop.fn_addr(fcinfo);
|
||||
resultnull = fcinfo->isnull;
|
||||
|
||||
/*
|
||||
* Reverse the result for NOT IN clauses since the above function
|
||||
* is the equality function and we need not-equals.
|
||||
*/
|
||||
if (!inclause)
|
||||
result = !result;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user