mirror of
https://github.com/postgres/postgres.git
synced 2025-05-05 09:19:17 +03:00
Better solution to the IN-list issue: instead of having an arbitrary cutoff,
treat Var and non-Var IN-list items differently. Only non-Var items are candidates to go into an ANY(ARRAY) construct --- we put all Vars as separate OR conditions on the grounds that that leaves more scope for optimization. Per suggestion from Robert Haas.
This commit is contained in:
parent
038e45d2cf
commit
0ee91fdfee
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198.2.1 2008/10/25 17:19:26 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198.2.2 2008/10/26 02:46:36 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -804,12 +804,14 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
|
|||||||
static Node *
|
static Node *
|
||||||
transformAExprIn(ParseState *pstate, A_Expr *a)
|
transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||||
{
|
{
|
||||||
|
Node *result = NULL;
|
||||||
Node *lexpr;
|
Node *lexpr;
|
||||||
List *rexprs;
|
List *rexprs;
|
||||||
|
List *rvars;
|
||||||
|
List *rnonvars;
|
||||||
List *typeids;
|
List *typeids;
|
||||||
bool useOr;
|
bool useOr;
|
||||||
bool haveRowExpr;
|
bool haveRowExpr;
|
||||||
Node *result;
|
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -825,43 +827,37 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
|||||||
* possible if the inputs are all scalars (no RowExprs) and there is a
|
* possible if the inputs are all scalars (no RowExprs) and there is a
|
||||||
* suitable array type available. If not, we fall back to a boolean
|
* suitable array type available. If not, we fall back to a boolean
|
||||||
* condition tree with multiple copies of the lefthand expression.
|
* condition tree with multiple copies of the lefthand expression.
|
||||||
|
* Also, any IN-list items that contain Vars are handled as separate
|
||||||
|
* boolean conditions, because that gives the planner more scope for
|
||||||
|
* optimization on such clauses.
|
||||||
*
|
*
|
||||||
* First step: transform all the inputs, and detect whether any are
|
* First step: transform all the inputs, and detect whether any are
|
||||||
* RowExprs.
|
* RowExprs or contain Vars.
|
||||||
*/
|
*/
|
||||||
lexpr = transformExpr(pstate, a->lexpr);
|
lexpr = transformExpr(pstate, a->lexpr);
|
||||||
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
|
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
|
||||||
typeids = list_make1_oid(exprType(lexpr));
|
typeids = list_make1_oid(exprType(lexpr));
|
||||||
rexprs = NIL;
|
rexprs = rvars = rnonvars = NIL;
|
||||||
foreach(l, (List *) a->rexpr)
|
foreach(l, (List *) a->rexpr)
|
||||||
{
|
{
|
||||||
Node *rexpr = transformExpr(pstate, lfirst(l));
|
Node *rexpr = transformExpr(pstate, lfirst(l));
|
||||||
|
|
||||||
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
|
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
|
||||||
rexprs = lappend(rexprs, rexpr);
|
rexprs = lappend(rexprs, rexpr);
|
||||||
typeids = lappend_oid(typeids, exprType(rexpr));
|
if (contain_vars_of_level(rexpr, 0))
|
||||||
|
rvars = lappend(rvars, rexpr);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rnonvars = lappend(rnonvars, rexpr);
|
||||||
|
typeids = lappend_oid(typeids, exprType(rexpr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We prefer a boolean tree to ScalarArrayOpExpr if any of these are true:
|
* ScalarArrayOpExpr is only going to be useful if there's more than
|
||||||
*
|
* one non-Var righthand item. Also, it won't work for RowExprs.
|
||||||
* 1. We have a RowExpr anywhere.
|
|
||||||
*
|
|
||||||
* 2. There's only one righthand expression --- best to just generate a
|
|
||||||
* simple = comparison.
|
|
||||||
*
|
|
||||||
* 3. There's a reasonably small number of righthand expressions and
|
|
||||||
* they contain any Vars. This is a heuristic to support cases like
|
|
||||||
* WHERE '555-1212' IN (tab.home_phone, tab.work_phone), which can be
|
|
||||||
* optimized into an OR of indexscans on different indexes so long as
|
|
||||||
* it's left as an OR tree. (It'd be better to leave this decision
|
|
||||||
* to the planner, no doubt, but the amount of code required to reformat
|
|
||||||
* the expression later on seems out of proportion to the benefit.)
|
|
||||||
*/
|
*/
|
||||||
if (!(haveRowExpr ||
|
if (!haveRowExpr && list_length(rnonvars) > 1)
|
||||||
list_length(rexprs) == 1 ||
|
|
||||||
(list_length(rexprs) <= 32 &&
|
|
||||||
contain_vars_of_level((Node *) rexprs, 0))))
|
|
||||||
{
|
{
|
||||||
Oid scalar_type;
|
Oid scalar_type;
|
||||||
Oid array_type;
|
Oid array_type;
|
||||||
@ -881,14 +877,14 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
|||||||
if (array_type != InvalidOid)
|
if (array_type != InvalidOid)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* OK: coerce all the right-hand inputs to the common type and
|
* OK: coerce all the right-hand non-Var inputs to the common type
|
||||||
* build an ArrayExpr for them.
|
* and build an ArrayExpr for them.
|
||||||
*/
|
*/
|
||||||
List *aexprs;
|
List *aexprs;
|
||||||
ArrayExpr *newa;
|
ArrayExpr *newa;
|
||||||
|
|
||||||
aexprs = NIL;
|
aexprs = NIL;
|
||||||
foreach(l, rexprs)
|
foreach(l, rnonvars)
|
||||||
{
|
{
|
||||||
Node *rexpr = (Node *) lfirst(l);
|
Node *rexpr = (Node *) lfirst(l);
|
||||||
|
|
||||||
@ -903,19 +899,21 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
|||||||
newa->elements = aexprs;
|
newa->elements = aexprs;
|
||||||
newa->multidims = false;
|
newa->multidims = false;
|
||||||
|
|
||||||
return (Node *) make_scalar_array_op(pstate,
|
result = (Node *) make_scalar_array_op(pstate,
|
||||||
a->name,
|
a->name,
|
||||||
useOr,
|
useOr,
|
||||||
lexpr,
|
lexpr,
|
||||||
(Node *) newa,
|
(Node *) newa,
|
||||||
a->location);
|
a->location);
|
||||||
|
|
||||||
|
/* Consider only the Vars (if any) in the loop below */
|
||||||
|
rexprs = rvars;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must do it the hard way, ie, with a boolean expression tree.
|
* Must do it the hard way, ie, with a boolean expression tree.
|
||||||
*/
|
*/
|
||||||
result = NULL;
|
|
||||||
foreach(l, rexprs)
|
foreach(l, rexprs)
|
||||||
{
|
{
|
||||||
Node *rexpr = (Node *) lfirst(l);
|
Node *rexpr = (Node *) lfirst(l);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user