mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
Tweak ExecIndexEvalRuntimeKeys to forcibly detoast any toasted comparison
values before they get passed to the index access method. This avoids repeated detoastings that will otherwise ensue as the comparison value is examined by various index support functions. We have seen a couple of reports of cases where repeated detoastings result in an order-of-magnitude slowdown, so it seems worth adding a bit of extra logic to prevent this. I had previously proposed trying to avoid duplicate detoastings in general, but this fix takes care of what seems the most important case in practice with very little effort or risk. Back-patch to 8.4 so that the PostGIS folk won't have to wait a year to have this fix in a production release. (The issue exists further back, of course, but the code's diverged enough to make backpatching further a higher-risk action. Also it appears that the possible gains may be limited in prior releases because of different handling of lossy operators.)
This commit is contained in:
parent
56e985d02e
commit
c38b75947e
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.133 2009/07/18 19:15:41 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.134 2009/08/23 18:26:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -238,6 +238,10 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
|
||||
IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
|
||||
{
|
||||
int j;
|
||||
MemoryContext oldContext;
|
||||
|
||||
/* We want to keep the key values in per-tuple memory */
|
||||
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
||||
|
||||
for (j = 0; j < numRuntimeKeys; j++)
|
||||
{
|
||||
@ -256,18 +260,32 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
|
||||
* econtext->ecxt_per_tuple_memory. We assume that the outer tuple
|
||||
* will stay put throughout our scan. If this is wrong, we could copy
|
||||
* the result into our context explicitly, but I think that's not
|
||||
* necessary...
|
||||
* necessary.
|
||||
*
|
||||
* It's also entirely possible that the result of the eval is a
|
||||
* toasted value. In this case we should forcibly detoast it,
|
||||
* to avoid repeat detoastings each time the value is examined
|
||||
* by an index support function.
|
||||
*/
|
||||
scanvalue = ExecEvalExprSwitchContext(key_expr,
|
||||
scanvalue = ExecEvalExpr(key_expr,
|
||||
econtext,
|
||||
&isNull,
|
||||
NULL);
|
||||
scan_key->sk_argument = scanvalue;
|
||||
if (isNull)
|
||||
{
|
||||
scan_key->sk_argument = scanvalue;
|
||||
scan_key->sk_flags |= SK_ISNULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (runtimeKeys[j].key_toastable)
|
||||
scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
|
||||
scan_key->sk_argument = scanvalue;
|
||||
scan_key->sk_flags &= ~SK_ISNULL;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -795,6 +813,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
|
||||
runtime_keys[n_runtime_keys].scan_key = this_scan_key;
|
||||
runtime_keys[n_runtime_keys].key_expr =
|
||||
ExecInitExpr(rightop, planstate);
|
||||
runtime_keys[n_runtime_keys].key_toastable =
|
||||
TypeIsToastable(op_righttype);
|
||||
n_runtime_keys++;
|
||||
scanvalue = (Datum) 0;
|
||||
}
|
||||
@ -843,34 +863,6 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
|
||||
|
||||
varattno = ((Var *) leftop)->varattno;
|
||||
|
||||
/*
|
||||
* rightop is the constant or variable comparison value
|
||||
*/
|
||||
rightop = (Expr *) lfirst(rargs_cell);
|
||||
rargs_cell = lnext(rargs_cell);
|
||||
|
||||
if (rightop && IsA(rightop, RelabelType))
|
||||
rightop = ((RelabelType *) rightop)->arg;
|
||||
|
||||
Assert(rightop != NULL);
|
||||
|
||||
if (IsA(rightop, Const))
|
||||
{
|
||||
/* OK, simple constant comparison value */
|
||||
scanvalue = ((Const *) rightop)->constvalue;
|
||||
if (((Const *) rightop)->constisnull)
|
||||
flags |= SK_ISNULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need to treat this one as a runtime key */
|
||||
runtime_keys[n_runtime_keys].scan_key = this_sub_key;
|
||||
runtime_keys[n_runtime_keys].key_expr =
|
||||
ExecInitExpr(rightop, planstate);
|
||||
n_runtime_keys++;
|
||||
scanvalue = (Datum) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to look up the operator's associated btree support
|
||||
* function
|
||||
@ -896,6 +888,36 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
|
||||
op_righttype,
|
||||
BTORDER_PROC);
|
||||
|
||||
/*
|
||||
* rightop is the constant or variable comparison value
|
||||
*/
|
||||
rightop = (Expr *) lfirst(rargs_cell);
|
||||
rargs_cell = lnext(rargs_cell);
|
||||
|
||||
if (rightop && IsA(rightop, RelabelType))
|
||||
rightop = ((RelabelType *) rightop)->arg;
|
||||
|
||||
Assert(rightop != NULL);
|
||||
|
||||
if (IsA(rightop, Const))
|
||||
{
|
||||
/* OK, simple constant comparison value */
|
||||
scanvalue = ((Const *) rightop)->constvalue;
|
||||
if (((Const *) rightop)->constisnull)
|
||||
flags |= SK_ISNULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need to treat this one as a runtime key */
|
||||
runtime_keys[n_runtime_keys].scan_key = this_sub_key;
|
||||
runtime_keys[n_runtime_keys].key_expr =
|
||||
ExecInitExpr(rightop, planstate);
|
||||
runtime_keys[n_runtime_keys].key_toastable =
|
||||
TypeIsToastable(op_righttype);
|
||||
n_runtime_keys++;
|
||||
scanvalue = (Datum) 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the subsidiary scan key's fields appropriately
|
||||
*/
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.206 2009/08/06 20:44:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.207 2009/08/23 18:26:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1084,6 +1084,7 @@ typedef struct
|
||||
{
|
||||
ScanKey scan_key; /* scankey to put value into */
|
||||
ExprState *key_expr; /* expr to evaluate to get value */
|
||||
bool key_toastable; /* is expr's result a toastable datatype? */
|
||||
} IndexRuntimeKeyInfo;
|
||||
|
||||
typedef struct
|
||||
|
Loading…
Reference in New Issue
Block a user