Skip to content

Commit 0aed62f

Browse files
committed
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.
1 parent aa0fb53 commit 0aed62f

File tree

1 file changed

+30
-34
lines changed

1 file changed

+30
-34
lines changed

src/backend/parser/parse_expr.c

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.236 2008/10/25 17:19:09 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.237 2008/10/26 02:46:25 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -939,11 +939,13 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
939939
static Node *
940940
transformAExprIn(ParseState *pstate, A_Expr *a)
941941
{
942+
Node *result = NULL;
942943
Node *lexpr;
943944
List *rexprs;
945+
List *rvars;
946+
List *rnonvars;
944947
bool useOr;
945948
bool haveRowExpr;
946-
Node *result;
947949
ListCell *l;
948950

949951
/*
@@ -959,41 +961,33 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
959961
* possible if the inputs are all scalars (no RowExprs) and there is a
960962
* suitable array type available. If not, we fall back to a boolean
961963
* condition tree with multiple copies of the lefthand expression.
964+
* Also, any IN-list items that contain Vars are handled as separate
965+
* boolean conditions, because that gives the planner more scope for
966+
* optimization on such clauses.
962967
*
963968
* First step: transform all the inputs, and detect whether any are
964-
* RowExprs.
969+
* RowExprs or contain Vars.
965970
*/
966971
lexpr = transformExpr(pstate, a->lexpr);
967972
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
968-
rexprs = NIL;
973+
rexprs = rvars = rnonvars = NIL;
969974
foreach(l, (List *) a->rexpr)
970975
{
971976
Node *rexpr = transformExpr(pstate, lfirst(l));
972977

973978
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
974979
rexprs = lappend(rexprs, rexpr);
980+
if (contain_vars_of_level(rexpr, 0))
981+
rvars = lappend(rvars, rexpr);
982+
else
983+
rnonvars = lappend(rnonvars, rexpr);
975984
}
976985

977986
/*
978-
* We prefer a boolean tree to ScalarArrayOpExpr if any of these are true:
979-
*
980-
* 1. We have a RowExpr anywhere.
981-
*
982-
* 2. There's only one righthand expression --- best to just generate a
983-
* simple = comparison.
984-
*
985-
* 3. There's a reasonably small number of righthand expressions and
986-
* they contain any Vars. This is a heuristic to support cases like
987-
* WHERE '555-1212' IN (tab.home_phone, tab.work_phone), which can be
988-
* optimized into an OR of indexscans on different indexes so long as
989-
* it's left as an OR tree. (It'd be better to leave this decision
990-
* to the planner, no doubt, but the amount of code required to reformat
991-
* the expression later on seems out of proportion to the benefit.)
987+
* ScalarArrayOpExpr is only going to be useful if there's more than
988+
* one non-Var righthand item. Also, it won't work for RowExprs.
992989
*/
993-
if (!(haveRowExpr ||
994-
list_length(rexprs) == 1 ||
995-
(list_length(rexprs) <= 32 &&
996-
contain_vars_of_level((Node *) rexprs, 0))))
990+
if (!haveRowExpr && list_length(rnonvars) > 1)
997991
{
998992
List *allexprs;
999993
Oid scalar_type;
@@ -1004,9 +998,9 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
1004998
* since the LHS' type is first in the list, it will be preferred when
1005999
* there is doubt (eg, when all the RHS items are unknown literals).
10061000
*
1007-
* Note: use list_concat here not lcons, to avoid damaging rexprs.
1001+
* Note: use list_concat here not lcons, to avoid damaging rnonvars.
10081002
*/
1009-
allexprs = list_concat(list_make1(lexpr), rexprs);
1003+
allexprs = list_concat(list_make1(lexpr), rnonvars);
10101004
scalar_type = select_common_type(pstate, allexprs, NULL, NULL);
10111005

10121006
/* Do we have an array type to use? */
@@ -1017,14 +1011,14 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
10171011
if (array_type != InvalidOid)
10181012
{
10191013
/*
1020-
* OK: coerce all the right-hand inputs to the common type and
1021-
* build an ArrayExpr for them.
1014+
* OK: coerce all the right-hand non-Var inputs to the common type
1015+
* and build an ArrayExpr for them.
10221016
*/
10231017
List *aexprs;
10241018
ArrayExpr *newa;
10251019

10261020
aexprs = NIL;
1027-
foreach(l, rexprs)
1021+
foreach(l, rnonvars)
10281022
{
10291023
Node *rexpr = (Node *) lfirst(l);
10301024

@@ -1040,19 +1034,21 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
10401034
newa->multidims = false;
10411035
newa->location = -1;
10421036

1043-
return (Node *) make_scalar_array_op(pstate,
1044-
a->name,
1045-
useOr,
1046-
lexpr,
1047-
(Node *) newa,
1048-
a->location);
1037+
result = (Node *) make_scalar_array_op(pstate,
1038+
a->name,
1039+
useOr,
1040+
lexpr,
1041+
(Node *) newa,
1042+
a->location);
1043+
1044+
/* Consider only the Vars (if any) in the loop below */
1045+
rexprs = rvars;
10491046
}
10501047
}
10511048

10521049
/*
10531050
* Must do it the hard way, ie, with a boolean expression tree.
10541051
*/
1055-
result = NULL;
10561052
foreach(l, rexprs)
10571053
{
10581054
Node *rexpr = (Node *) lfirst(l);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy