提交 d5375491 编写于 作者: T Tom Lane

Improve management of "sticky" entries in contrib/pg_stat_statements.

This patch addresses a deficiency in the previous pg_stat_statements patch.
We want to give sticky entries an initial "usage" factor high enough that
they probably will stick around until their query is completed.  However,
if the query never completes (eg it gets an error during execution), the
entry shouldn't persist indefinitely.  Manage this by starting out with
a usage setting equal to the (approximate) median usage value within the
whole hashtable, but decaying the value much more aggressively than we
do for normal entries.

Peter Geoghegan
上级 03529a3f
......@@ -72,8 +72,9 @@ static const uint32 PGSS_FILE_HEADER = 0x20120328;
/* XXX: Should USAGE_EXEC reflect execution time and/or buffer usage? */
#define USAGE_EXEC(duration) (1.0)
#define USAGE_INIT (1.0) /* including initial planning */
#define USAGE_NON_EXEC_STICK (3.0) /* to make new entries sticky */
#define ASSUMED_MEDIAN_INIT (10.0) /* initial assumed median usage */
#define USAGE_DECREASE_FACTOR (0.99) /* decreased every entry_dealloc */
#define STICKY_DECREASE_FACTOR (0.50) /* factor for sticky entries */
#define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
#define JUMBLE_SIZE 1024 /* query serialization buffer size */
......@@ -139,6 +140,7 @@ typedef struct pgssSharedState
{
LWLockId lock; /* protects hashtable search/modification */
int query_size; /* max query length in bytes */
double cur_median_usage; /* current median usage in hashtable */
} pgssSharedState;
/*
......@@ -413,6 +415,7 @@ pgss_shmem_startup(void)
/* First time through ... */
pgss->lock = LWLockAssign();
pgss->query_size = pgstat_track_activity_query_size;
pgss->cur_median_usage = ASSUMED_MEDIAN_INIT;
}
/* Be sure everyone agrees on the hash table entry size */
......@@ -908,7 +911,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
/*
* Given an arbitrarily long query string, produce a hash for the purposes of
* identifying the query, without normalizing constants. Used when hashing
* utility statements, or for legacy compatibility mode.
* utility statements.
*/
static uint32
pgss_hash_string(const char *str)
......@@ -951,17 +954,28 @@ pgss_store(const char *query, uint32 queryId,
entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
/*
* When creating an entry just to store the normalized string, make it
* artificially sticky so that it will probably still be there when
* executed. Strictly speaking, query strings are normalized on a best
* effort basis, though it would be difficult to demonstrate this even
* under artificial conditions.
*/
if (jstate && !entry)
usage = USAGE_NON_EXEC_STICK;
if (jstate)
{
/*
* When creating an entry just to store the normalized string, make it
* artificially sticky so that it will probably still be there when
* the query gets executed. We do this by giving it a median usage
* value rather than the normal value. (Strictly speaking, query
* strings are normalized on a best effort basis, though it would be
* difficult to demonstrate this even under artificial conditions.)
* But if we found the entry already present, don't let this call
* increment its usage.
*/
if (!entry)
usage = pgss->cur_median_usage;
else
usage = 0;
}
else
{
/* normal case, increment usage by normal amount */
usage = USAGE_EXEC(duration);
}
if (!entry)
{
......@@ -1185,8 +1199,8 @@ pg_stat_statements(PG_FUNCTION_ARGS)
values[i++] = Float8GetDatumFast(tmp.time_write);
}
Assert(i == sql_supports_v1_1_counters ?
PG_STAT_STATEMENTS_COLS : PG_STAT_STATEMENTS_COLS_V1_0);
Assert(i == (sql_supports_v1_1_counters ?
PG_STAT_STATEMENTS_COLS : PG_STAT_STATEMENTS_COLS_V1_0));
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
......@@ -1288,7 +1302,11 @@ entry_dealloc(void)
int nvictims;
int i;
/* Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them. */
/*
* Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
* While we're scanning the table, apply the decay factor to the usage
* values.
*/
entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
......@@ -1297,10 +1315,19 @@ entry_dealloc(void)
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
entries[i++] = entry;
entry->counters.usage *= USAGE_DECREASE_FACTOR;
/* "Sticky" entries get a different usage decay rate. */
if (entry->counters.calls == 0)
entry->counters.usage *= STICKY_DECREASE_FACTOR;
else
entry->counters.usage *= USAGE_DECREASE_FACTOR;
}
qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
/* Also, record the (approximate) median usage */
if (i > 0)
pgss->cur_median_usage = entries[i / 2]->counters.usage;
nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
nvictims = Min(nvictims, i);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册