1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

Restructure planning of nestloop inner indexscans so that the set of usable

joinclauses is determined accurately for each join.  Formerly, the code only
considered joinclauses that used all of the rels from the outer side of the
join; thus for example
	FROM (a CROSS JOIN b) JOIN c ON (c.f1 = a.x AND c.f2 = b.y)
could not exploit a two-column index on c(f1,f2), since neither of the
qual clauses would be in the joininfo list it looked in.  The new code does
this correctly, and also is able to eliminate redundant clauses, thus fixing
the problem noted 24-Oct-02 by Hans-Jürgen Schönig.
This commit is contained in:
Tom Lane
2002-11-24 21:52:15 +00:00
parent 6bfc09baf4
commit 04c8785c7b
19 changed files with 742 additions and 579 deletions

View File

@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.220 2002/11/23 03:59:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.221 2002/11/24 21:52:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1148,7 +1148,9 @@ _copyRelOptInfo(RelOptInfo *from)
newnode->baserestrictcost = from->baserestrictcost;
newnode->outerjoinset = listCopy(from->outerjoinset);
Node_Copy(from, newnode, joininfo);
Node_Copy(from, newnode, innerjoin);
newnode->index_outer_relids = listCopy(from->index_outer_relids);
Node_Copy(from, newnode, index_inner_paths);
return newnode;
}
@@ -1200,6 +1202,9 @@ _copyIndexOptInfo(IndexOptInfo *from)
Node_Copy(from, newnode, indpred);
newnode->unique = from->unique;
newnode->outer_relids = listCopy(from->outer_relids);
Node_Copy(from, newnode, inner_paths);
return newnode;
}
@@ -1262,8 +1267,6 @@ _copyIndexPath(IndexPath *from)
Node_Copy(from, newnode, indexinfo);
Node_Copy(from, newnode, indexqual);
newnode->indexscandir = from->indexscandir;
newnode->joinrelids = listCopy(from->joinrelids);
newnode->alljoinquals = from->alljoinquals;
newnode->rows = from->rows;
return newnode;
@@ -1491,6 +1494,25 @@ _copyJoinInfo(JoinInfo *from)
return newnode;
}
/* ----------------
* _copyInnerIndexscanInfo
* ----------------
*/
static InnerIndexscanInfo *
_copyInnerIndexscanInfo(InnerIndexscanInfo *from)
{
InnerIndexscanInfo *newnode = makeNode(InnerIndexscanInfo);
/*
* copy remainder of node
*/
newnode->other_relids = listCopy(from->other_relids);
newnode->isouterjoin = from->isouterjoin;
Node_Copy(from, newnode, best_innerpath);
return newnode;
}
/* ****************************************************************
* parsenodes.h copy functions
* ****************************************************************
@@ -2952,6 +2974,9 @@ copyObject(void *from)
case T_IndexOptInfo:
retval = _copyIndexOptInfo(from);
break;
case T_InnerIndexscanInfo:
retval = _copyInnerIndexscanInfo(from);
break;
/*
* VALUE NODES

View File

@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.166 2002/11/23 03:59:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.167 2002/11/24 21:52:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -429,10 +429,6 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
return false;
if (a->indexscandir != b->indexscandir)
return false;
if (!equali(a->joinrelids, b->joinrelids))
return false;
if (a->alljoinquals != b->alljoinquals)
return false;
/*
* Skip 'rows' because of possibility of floating-point roundoff
@@ -548,13 +544,11 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
return false;
/*
* We ignore eval_cost, this_selec, left/right_pathkey, and
* left/right_bucketsize, since they may not be set yet, and should be
* derivable from the clause anyway. Probably it's not really
* necessary to compare any of these remaining fields ...
* We ignore subclauseindices, eval_cost, this_selec, left/right_pathkey,
* and left/right_bucketsize, since they may not be set yet, and should be
* derivable from the clause anyway. Probably it's not really necessary
* to compare any of these remaining fields ...
*/
if (!equal(a->subclauseindices, b->subclauseindices))
return false;
if (a->mergejoinoperator != b->mergejoinoperator)
return false;
if (a->left_sortop != b->left_sortop)
@@ -576,6 +570,18 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
return true;
}
static bool
_equalInnerIndexscanInfo(InnerIndexscanInfo *a, InnerIndexscanInfo *b)
{
if (!equali(a->other_relids, b->other_relids))
return false;
if (a->isouterjoin != b->isouterjoin)
return false;
if (!equal(a->best_innerpath, b->best_innerpath))
return false;
return true;
}
/*
* Stuff from parsenodes.h
*/
@@ -2120,6 +2126,9 @@ equal(void *a, void *b)
case T_JoinInfo:
retval = _equalJoinInfo(a, b);
break;
case T_InnerIndexscanInfo:
retval = _equalInnerIndexscanInfo(a, b);
break;
case T_TidPath:
retval = _equalTidPath(a, b);
break;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.41 2002/06/20 20:29:29 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.42 2002/11/24 21:52:13 tgl Exp $
*
* NOTES
* XXX a few of the following functions are duplicated to handle
@@ -372,6 +372,46 @@ set_unioni(List *l1, List *l2)
return retval;
}
/*
* Generate the intersection of two lists,
* ie, all members of both l1 and l2.
*
* NOTE: if there are duplicates in l1 they will still be duplicate in the
* result; but duplicates in l2 are discarded.
*
* The result is a fresh List, but it points to the same member nodes
* as were in the inputs.
*/
#ifdef NOT_USED
List *
set_intersect(List *l1, List *l2)
{
List *retval = NIL;
List *i;
foreach(i, l1)
{
if (member(lfirst(i), l2))
retval = lappend(retval, lfirst(i));
}
return retval;
}
#endif
List *
set_intersecti(List *l1, List *l2)
{
List *retval = NIL;
List *i;
foreach(i, l1)
{
if (intMember(lfirsti(i), l2))
retval = lappendi(retval, lfirsti(i));
}
return retval;
}
/*
* member()
* nondestructive, returns t iff l1 is a member of the list l2

View File

@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.180 2002/11/15 02:50:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.181 2002/11/24 21:52:13 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1067,12 +1067,8 @@ _outIndexPath(StringInfo str, IndexPath *node)
appendStringInfo(str, " :indexqual ");
_outNode(str, node->indexqual);
appendStringInfo(str, " :indexscandir %d :joinrelids ",
(int) node->indexscandir);
_outIntList(str, node->joinrelids);
appendStringInfo(str, " :alljoinquals %s :rows %.2f ",
booltostr(node->alljoinquals),
appendStringInfo(str, " :indexscandir %d :rows %.2f ",
(int) node->indexscandir,
node->rows);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.137 2002/11/15 02:50:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.138 2002/11/24 21:52:13 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
@@ -1824,13 +1824,6 @@ _readIndexPath(void)
token = pg_strtok(&length); /* now read it */
local_node->indexscandir = (ScanDirection) atoi(token);
token = pg_strtok(&length); /* get :joinrelids */
local_node->joinrelids = toIntList(nodeRead(true));
token = pg_strtok(&length); /* get :alljoinquals */
token = pg_strtok(&length); /* now read it */
local_node->alljoinquals = strtobool(token);
token = pg_strtok(&length); /* get :rows */
token = pg_strtok(&length); /* now read it */
local_node->rows = atof(token);