Commit b0c4a50b authored by Tom Lane's avatar Tom Lane

Instead of rechecking lossy index operators by putting them into the

regular qpqual ('filter condition'), add special-purpose code to
nodeIndexscan.c to recheck them.  This ends being almost no net addition
of code, because the removal of planner code balances out the extra
executor code, but it is significantly more efficient when a lossy
operator is involved in an OR indexscan.  The old implementation had
to recheck the entire indexqual in such cases.
parent fa559a86
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.88 2003/12/30 20:05:05 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.89 2004/01/06 04:31:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -99,7 +99,9 @@ IndexNext(IndexScanState *node) ...@@ -99,7 +99,9 @@ IndexNext(IndexScanState *node)
ExprContext *econtext; ExprContext *econtext;
ScanDirection direction; ScanDirection direction;
IndexScanDescPtr scanDescs; IndexScanDescPtr scanDescs;
List **lossyQuals;
IndexScanDesc scandesc; IndexScanDesc scandesc;
List *lossyQual;
Index scanrelid; Index scanrelid;
HeapTuple tuple; HeapTuple tuple;
TupleTableSlot *slot; TupleTableSlot *slot;
...@@ -120,6 +122,7 @@ IndexNext(IndexScanState *node) ...@@ -120,6 +122,7 @@ IndexNext(IndexScanState *node)
direction = ForwardScanDirection; direction = ForwardScanDirection;
} }
scanDescs = node->iss_ScanDescs; scanDescs = node->iss_ScanDescs;
lossyQuals = node->iss_LossyQuals;
numIndices = node->iss_NumIndices; numIndices = node->iss_NumIndices;
econtext = node->ss.ps.ps_ExprContext; econtext = node->ss.ps.ps_ExprContext;
slot = node->ss.ss_ScanTupleSlot; slot = node->ss.ss_ScanTupleSlot;
...@@ -188,6 +191,8 @@ IndexNext(IndexScanState *node) ...@@ -188,6 +191,8 @@ IndexNext(IndexScanState *node)
while (indexNumber < numIndices) while (indexNumber < numIndices)
{ {
scandesc = scanDescs[node->iss_IndexPtr]; scandesc = scanDescs[node->iss_IndexPtr];
lossyQual = lossyQuals[node->iss_IndexPtr];
while ((tuple = index_getnext(scandesc, direction)) != NULL) while ((tuple = index_getnext(scandesc, direction)) != NULL)
{ {
/* /*
...@@ -201,6 +206,22 @@ IndexNext(IndexScanState *node) ...@@ -201,6 +206,22 @@ IndexNext(IndexScanState *node)
scandesc->xs_cbuf, /* buffer containing tuple */ scandesc->xs_cbuf, /* buffer containing tuple */
false); /* don't pfree */ false); /* don't pfree */
/*
* If any of the index operators involved in this scan are lossy,
* recheck them by evaluating the original operator clauses.
*/
if (lossyQual)
{
econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
if (!ExecQual(lossyQual, econtext, false))
{
/* Fails lossy op, so drop it and loop back for another */
ExecClearTuple(slot);
continue;
}
}
/* /*
* If it's a multiple-index scan, make sure not to double-report * If it's a multiple-index scan, make sure not to double-report
* a tuple matched by more than one index. (See notes above.) * a tuple matched by more than one index. (See notes above.)
...@@ -615,6 +636,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -615,6 +636,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
List *indxqual; List *indxqual;
List *indxstrategy; List *indxstrategy;
List *indxsubtype; List *indxsubtype;
List *indxlossy;
List *indxid; List *indxid;
int i; int i;
int numIndices; int numIndices;
...@@ -623,6 +645,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -623,6 +645,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
int *numScanKeys; int *numScanKeys;
RelationPtr indexDescs; RelationPtr indexDescs;
IndexScanDescPtr scanDescs; IndexScanDescPtr scanDescs;
List **lossyQuals;
ExprState ***runtimeKeyInfo; ExprState ***runtimeKeyInfo;
bool have_runtime_keys; bool have_runtime_keys;
RangeTblEntry *rtentry; RangeTblEntry *rtentry;
...@@ -680,6 +703,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -680,6 +703,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indexstate->iss_RuntimeKeysReady = false; indexstate->iss_RuntimeKeysReady = false;
indexstate->iss_RelationDescs = NULL; indexstate->iss_RelationDescs = NULL;
indexstate->iss_ScanDescs = NULL; indexstate->iss_ScanDescs = NULL;
indexstate->iss_LossyQuals = NULL;
/* /*
* get the index node information * get the index node information
...@@ -699,6 +723,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -699,6 +723,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey)); scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation)); indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc)); scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
lossyQuals = (List **) palloc0(numIndices * sizeof(List *));
/* /*
* initialize space for runtime key info (may not be needed) * initialize space for runtime key info (may not be needed)
...@@ -712,11 +737,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -712,11 +737,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indxqual = node->indxqual; indxqual = node->indxqual;
indxstrategy = node->indxstrategy; indxstrategy = node->indxstrategy;
indxsubtype = node->indxsubtype; indxsubtype = node->indxsubtype;
indxlossy = node->indxlossy;
for (i = 0; i < numIndices; i++) for (i = 0; i < numIndices; i++)
{ {
List *quals; List *quals;
List *strategies; List *strategies;
List *subtypes; List *subtypes;
List *lossyflags;
int n_keys; int n_keys;
ScanKey scan_keys; ScanKey scan_keys;
ExprState **run_keys; ExprState **run_keys;
...@@ -728,6 +755,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -728,6 +755,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indxstrategy = lnext(indxstrategy); indxstrategy = lnext(indxstrategy);
subtypes = lfirst(indxsubtype); subtypes = lfirst(indxsubtype);
indxsubtype = lnext(indxsubtype); indxsubtype = lnext(indxsubtype);
lossyflags = lfirst(indxlossy);
indxlossy = lnext(indxlossy);
n_keys = length(quals); n_keys = length(quals);
scan_keys = (n_keys <= 0) ? (ScanKey) NULL : scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
(ScanKey) palloc(n_keys * sizeof(ScanKeyData)); (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
...@@ -747,6 +776,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -747,6 +776,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
AttrNumber varattno; /* att number used in scan */ AttrNumber varattno; /* att number used in scan */
StrategyNumber strategy; /* op's strategy number */ StrategyNumber strategy; /* op's strategy number */
Oid subtype; /* op's strategy subtype */ Oid subtype; /* op's strategy subtype */
int lossy; /* op's recheck flag */
RegProcedure opfuncid; /* operator proc id used in scan */ RegProcedure opfuncid; /* operator proc id used in scan */
Datum scanvalue; /* value used in scan (if const) */ Datum scanvalue; /* value used in scan (if const) */
...@@ -759,6 +789,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -759,6 +789,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
strategies = lnext(strategies); strategies = lnext(strategies);
subtype = lfirsto(subtypes); subtype = lfirsto(subtypes);
subtypes = lnext(subtypes); subtypes = lnext(subtypes);
lossy = lfirsti(lossyflags);
lossyflags = lnext(lossyflags);
if (!IsA(clause, OpExpr)) if (!IsA(clause, OpExpr))
elog(ERROR, "indxqual is not an OpExpr"); elog(ERROR, "indxqual is not an OpExpr");
...@@ -839,6 +871,20 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -839,6 +871,20 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
subtype, /* strategy subtype */ subtype, /* strategy subtype */
opfuncid, /* reg proc to use */ opfuncid, /* reg proc to use */
scanvalue); /* constant */ scanvalue); /* constant */
/*
* If this operator is lossy, add its indxqualorig expression
* to the list of quals to recheck. The nth() calls here could
* be avoided by chasing the lists in parallel to all the other
* lists, but since lossy operators are very uncommon, it's
* probably a waste of time to do so.
*/
if (lossy)
{
lossyQuals[i] = lappend(lossyQuals[i],
nth(j,
(List *) nth(i, indexstate->indxqualorig)));
}
} }
/* /*
...@@ -928,6 +974,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate) ...@@ -928,6 +974,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indexstate->iss_RelationDescs = indexDescs; indexstate->iss_RelationDescs = indexDescs;
indexstate->iss_ScanDescs = scanDescs; indexstate->iss_ScanDescs = scanDescs;
indexstate->iss_LossyQuals = lossyQuals;
/* /*
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.273 2004/01/05 05:07:35 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.274 2004/01/06 04:31:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -284,6 +284,17 @@ _copyIndexScan(IndexScan *from) ...@@ -284,6 +284,17 @@ _copyIndexScan(IndexScan *from)
} }
newnode->indxsubtype = newsubtype; newnode->indxsubtype = newsubtype;
} }
/* this can become COPY_NODE_FIELD when intlists are normal objects: */
{
List *newstrat = NIL;
List *tmp;
foreach(tmp, from->indxlossy)
{
newstrat = lappend(newstrat, listCopy(lfirst(tmp)));
}
newnode->indxlossy = newstrat;
}
COPY_SCALAR_FIELD(indxorderdir); COPY_SCALAR_FIELD(indxorderdir);
return newnode; return newnode;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.228 2004/01/05 23:39:53 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.229 2004/01/06 04:31:01 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -356,6 +356,16 @@ _outIndexScan(StringInfo str, IndexScan *node) ...@@ -356,6 +356,16 @@ _outIndexScan(StringInfo str, IndexScan *node)
_outOidList(str, lfirst(tmp)); _outOidList(str, lfirst(tmp));
} }
} }
/* this can become WRITE_NODE_FIELD when intlists are normal objects: */
{
List *tmp;
appendStringInfo(str, " :indxlossy ");
foreach(tmp, node->indxlossy)
{
_outIntList(str, lfirst(tmp));
}
}
WRITE_ENUM_FIELD(indxorderdir, ScanDirection); WRITE_ENUM_FIELD(indxorderdir, ScanDirection);
} }
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.121 2004/01/05 23:39:54 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.122 2004/01/06 04:31:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -384,10 +384,6 @@ cost_index(Path *path, Query *root, ...@@ -384,10 +384,6 @@ cost_index(Path *path, Query *root,
* some of the indexquals are join clauses and shouldn't be * some of the indexquals are join clauses and shouldn't be
* subtracted. Rather than work out exactly how much to subtract, we * subtracted. Rather than work out exactly how much to subtract, we
* don't subtract anything. * don't subtract anything.
*
* XXX For a lossy index, not all the quals will be removed and so we
* really shouldn't subtract their costs; but detecting that seems
* more expensive than it's worth.
*/ */
startup_cost += baserel->baserestrictcost.startup; startup_cost += baserel->baserestrictcost.startup;
cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple; cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
...@@ -397,6 +393,7 @@ cost_index(Path *path, Query *root, ...@@ -397,6 +393,7 @@ cost_index(Path *path, Query *root,
QualCost index_qual_cost; QualCost index_qual_cost;
cost_qual_eval(&index_qual_cost, indexQuals); cost_qual_eval(&index_qual_cost, indexQuals);
/* any startup cost still has to be paid ... */
cpu_per_tuple -= index_qual_cost.per_tuple; cpu_per_tuple -= index_qual_cost.per_tuple;
} }
......
This diff is collapsed.
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.99 2003/11/29 19:51:50 pgsql Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.100 2004/01/06 04:31:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -362,8 +362,8 @@ set_join_references(Join *join, List *rtable) ...@@ -362,8 +362,8 @@ set_join_references(Join *join, List *rtable)
/* /*
* We must fix the inner qpqual too, if it has join * We must fix the inner qpqual too, if it has join
* clauses (this could happen if the index is lossy: some * clauses (this could happen if special operators are
* indxquals may get rechecked as qpquals). * involved: some indxquals may get rechecked as qpquals).
*/ */
if (NumRelids((Node *) inner_plan->qual) > 1) if (NumRelids((Node *) inner_plan->qual) > 1)
inner_plan->qual = join_references(inner_plan->qual, inner_plan->qual = join_references(inner_plan->qual,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.109 2003/12/18 22:23:42 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.110 2004/01/06 04:31:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -776,6 +776,7 @@ typedef ScanState SeqScanState; ...@@ -776,6 +776,7 @@ typedef ScanState SeqScanState;
* RuntimeKeysReady true if runtime Skeys have been computed * RuntimeKeysReady true if runtime Skeys have been computed
* RelationDescs ptr to array of relation descriptors * RelationDescs ptr to array of relation descriptors
* ScanDescs ptr to array of scan descriptors * ScanDescs ptr to array of scan descriptors
* LossyQuals ptr to array of qual lists for lossy operators
* DupHash hashtable for recognizing dups in multiple scan * DupHash hashtable for recognizing dups in multiple scan
* MaxHash max # entries we will allow in hashtable * MaxHash max # entries we will allow in hashtable
* ---------------- * ----------------
...@@ -795,6 +796,7 @@ typedef struct IndexScanState ...@@ -795,6 +796,7 @@ typedef struct IndexScanState
bool iss_RuntimeKeysReady; bool iss_RuntimeKeysReady;
RelationPtr iss_RelationDescs; RelationPtr iss_RelationDescs;
IndexScanDescPtr iss_ScanDescs; IndexScanDescPtr iss_ScanDescs;
List **iss_LossyQuals;
HTAB *iss_DupHash; HTAB *iss_DupHash;
long iss_MaxHash; long iss_MaxHash;
} IndexScanState; } IndexScanState;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.72 2003/11/29 22:41:06 pgsql Exp $ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.73 2004/01/06 04:31:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -166,6 +166,7 @@ typedef struct IndexScan ...@@ -166,6 +166,7 @@ typedef struct IndexScan
List *indxqualorig; /* the same in original form */ List *indxqualorig; /* the same in original form */
List *indxstrategy; /* list of sublists of strategy numbers */ List *indxstrategy; /* list of sublists of strategy numbers */
List *indxsubtype; /* list of sublists of strategy subtypes */ List *indxsubtype; /* list of sublists of strategy subtypes */
List *indxlossy; /* list of sublists of lossy flags (ints) */
ScanDirection indxorderdir; /* forward or backward or don't care */ ScanDirection indxorderdir; /* forward or backward or don't care */
} IndexScan; } IndexScan;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment