mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
Replace nth() calls in inner loops with traversal of the list via
lnext, to eliminate O(N^2) behavior with lots of indexquals.
This commit is contained in:
parent
78296c2797
commit
60be6da731
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.45 2000/01/26 05:56:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.46 2000/02/05 23:19:44 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -124,7 +124,7 @@ IndexNext(IndexScan *node)
|
|||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
int iptr;
|
List *qual;
|
||||||
|
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
||||||
@ -134,20 +134,23 @@ IndexNext(IndexScan *node)
|
|||||||
slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
|
slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
|
||||||
slot->ttc_shouldFree = false;
|
slot->ttc_shouldFree = false;
|
||||||
|
|
||||||
for (iptr = 0; iptr < numIndices; iptr++)
|
scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
|
||||||
|
|
||||||
|
/* Does the tuple meet any of the OR'd indxqual conditions? */
|
||||||
|
foreach(qual, node->indxqualorig)
|
||||||
{
|
{
|
||||||
scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
|
if (ExecQual((List *) lfirst(qual),
|
||||||
if (ExecQual(nth(iptr, node->indxqualorig),
|
|
||||||
scanstate->cstate.cs_ExprContext,
|
scanstate->cstate.cs_ExprContext,
|
||||||
false))
|
false))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (iptr == numIndices) /* would not be returned by indices */
|
if (qual == NIL) /* would not be returned by indices */
|
||||||
slot->val = NULL;
|
slot->val = NULL;
|
||||||
|
|
||||||
/* Flag for the next call that no more tuples */
|
/* Flag for the next call that no more tuples */
|
||||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
||||||
return (slot);
|
|
||||||
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple = &(indexstate->iss_htup);
|
tuple = &(indexstate->iss_htup);
|
||||||
@ -189,14 +192,14 @@ IndexNext(IndexScan *node)
|
|||||||
{
|
{
|
||||||
bool prev_matches = false;
|
bool prev_matches = false;
|
||||||
int prev_index;
|
int prev_index;
|
||||||
|
List *qual;
|
||||||
|
|
||||||
/* ----------------
|
/*
|
||||||
* store the scanned tuple in the scan tuple slot of
|
* store the scanned tuple in the scan tuple slot of
|
||||||
* the scan state. Eventually we will only do this and not
|
* the scan state. Eventually we will only do this and not
|
||||||
* return a tuple. Note: we pass 'false' because tuples
|
* return a tuple. Note: we pass 'false' because tuples
|
||||||
* returned by amgetnext are pointers onto disk pages and
|
* returned by amgetnext are pointers onto disk pages and
|
||||||
* must not be pfree()'d.
|
* must not be pfree()'d.
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
ExecStoreTuple(tuple, /* tuple to store */
|
ExecStoreTuple(tuple, /* tuple to store */
|
||||||
slot, /* slot to store in */
|
slot, /* slot to store in */
|
||||||
@ -211,28 +214,29 @@ IndexNext(IndexScan *node)
|
|||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must check to see if the current tuple would have
|
* We must check to see if the current tuple was already
|
||||||
* been matched by an earlier index, so we don't double
|
* matched by an earlier index, so we don't double-report it.
|
||||||
* report it. We do this by passing the tuple through
|
* We do this by passing the tuple through ExecQual and
|
||||||
* ExecQual and look for failure with all previous
|
* checking for failure with all previous qualifications.
|
||||||
* qualifications.
|
|
||||||
*/
|
*/
|
||||||
|
scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
|
||||||
|
qual = node->indxqualorig;
|
||||||
for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
|
for (prev_index = 0; prev_index < indexstate->iss_IndexPtr;
|
||||||
prev_index++)
|
prev_index++)
|
||||||
{
|
{
|
||||||
scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
|
if (ExecQual((List *) lfirst(qual),
|
||||||
if (ExecQual(nth(prev_index, node->indxqualorig),
|
|
||||||
scanstate->cstate.cs_ExprContext,
|
scanstate->cstate.cs_ExprContext,
|
||||||
false))
|
false))
|
||||||
{
|
{
|
||||||
prev_matches = true;
|
prev_matches = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
qual = lnext(qual);
|
||||||
}
|
}
|
||||||
if (!prev_matches)
|
if (!prev_matches)
|
||||||
return slot;
|
return slot; /* OK to return tuple */
|
||||||
else
|
/* Duplicate tuple, so drop it and loop back for another */
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (indexNumber < numIndices)
|
if (indexNumber < numIndices)
|
||||||
@ -329,7 +333,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
scanDescs = indexstate->iss_ScanDescs;
|
scanDescs = indexstate->iss_ScanDescs;
|
||||||
scanKeys = indexstate->iss_ScanKeys;
|
scanKeys = indexstate->iss_ScanKeys;
|
||||||
runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
|
runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
|
||||||
indxqual = node->indxqual;
|
|
||||||
numScanKeys = indexstate->iss_NumScanKeys;
|
numScanKeys = indexstate->iss_NumScanKeys;
|
||||||
indexstate->iss_IndexPtr = -1;
|
indexstate->iss_IndexPtr = -1;
|
||||||
if (ScanDirectionIsBackward(node->indxorderdir))
|
if (ScanDirectionIsBackward(node->indxorderdir))
|
||||||
@ -352,9 +355,11 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* get the index qualifications and recalculate the appropriate values
|
* get the index qualifications and recalculate the appropriate values
|
||||||
*/
|
*/
|
||||||
|
indxqual = node->indxqual;
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
qual = nth(i, indxqual);
|
qual = lfirst(indxqual);
|
||||||
|
indxqual = lnext(indxqual);
|
||||||
n_keys = numScanKeys[i];
|
n_keys = numScanKeys[i];
|
||||||
scan_keys = (ScanKey) scanKeys[i];
|
scan_keys = (ScanKey) scanKeys[i];
|
||||||
|
|
||||||
@ -672,7 +677,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
indxid = node->indxid;
|
indxid = node->indxid;
|
||||||
indxqual = node->indxqual;
|
|
||||||
numIndices = length(indxid);
|
numIndices = length(indxid);
|
||||||
indexPtr = -1;
|
indexPtr = -1;
|
||||||
|
|
||||||
@ -701,6 +705,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
* build the index scan keys from the index qualification
|
* build the index scan keys from the index qualification
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
indxqual = node->indxqual;
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
@ -709,7 +714,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
ScanKey scan_keys;
|
ScanKey scan_keys;
|
||||||
int *run_keys;
|
int *run_keys;
|
||||||
|
|
||||||
qual = nth(i, indxqual);
|
qual = lfirst(indxqual);
|
||||||
|
indxqual = lnext(indxqual);
|
||||||
n_keys = length(qual);
|
n_keys = length(qual);
|
||||||
scan_keys = (n_keys <= 0) ? NULL :
|
scan_keys = (n_keys <= 0) ? NULL :
|
||||||
(ScanKey) palloc(n_keys * sizeof(ScanKeyData));
|
(ScanKey) palloc(n_keys * sizeof(ScanKeyData));
|
||||||
@ -743,8 +749,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
clause = nth(j, qual);
|
clause = nth(j, qual);
|
||||||
|
|
||||||
op = (Oper *) clause->oper;
|
op = (Oper *) clause->oper;
|
||||||
if (!IsA(op, Oper))
|
if (!IsA(clause, Expr) || !IsA(op, Oper))
|
||||||
elog(ERROR, "ExecInitIndexScan: op not an Oper!");
|
elog(ERROR, "ExecInitIndexScan: indxqual not an opclause!");
|
||||||
|
|
||||||
opid = op->opid;
|
opid = op->opid;
|
||||||
|
|
||||||
@ -1066,9 +1072,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
*/
|
*/
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
Oid indexOid;
|
Oid indexOid = (Oid) nthi(i, indxid);
|
||||||
|
|
||||||
indexOid = (Oid) nthi(i, indxid);
|
|
||||||
|
|
||||||
if (indexOid != 0)
|
if (indexOid != 0)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user