diff contrib/pg_stat_statements/pg_stat_statements.c index 178fdb9..823a62d *** a/contrib/pg_stat_statements/pg_stat_statements.c --- b/contrib/pg_stat_statements/pg_stat_statements.c *************** static const uint32 PGSS_FILE_HEADER = 0 *** 72,79 **** /* 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 USAGE_DECREASE_FACTOR (0.99) /* decreased every entry_dealloc */ #define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */ #define JUMBLE_SIZE 1024 /* query serialization buffer size */ --- 72,80 ---- /* 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 ASSUMED_MED_INIT (10.0) /* initial assumed median usage */ #define USAGE_DECREASE_FACTOR (0.99) /* decreased every entry_dealloc */ + #define STICKY_DECREASE_FACTOR (0.50) /* separate sticky decrease factor */ #define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */ #define JUMBLE_SIZE 1024 /* query serialization buffer size */ *************** typedef struct pgssSharedState *** 139,144 **** --- 140,146 ---- { LWLockId lock; /* protects hashtable search/modification */ int query_size; /* max query length in bytes */ + double cur_med_usage; /* current median of usage for hashtable */ } pgssSharedState; /* *************** pgss_shmem_startup(void) *** 413,418 **** --- 415,421 ---- /* First time through ... */ pgss->lock = LWLockAssign(); pgss->query_size = pgstat_track_activity_query_size; + pgss->cur_med_usage = ASSUMED_MED_INIT; } /* Be sure everyone agrees on the hash table entry size */ *************** pgss_match_fn(const void *key1, const vo *** 908,914 **** /* * 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. */ static uint32 pgss_hash_string(const char *str) --- 911,917 ---- /* * Given an arbitrarily long query string, produce a hash for the purposes of * identifying the query, without normalizing constants. Used when hashing ! * utility statements. */ static uint32 pgss_hash_string(const char *str) *************** pgss_store(const char *query, uint32 que *** 959,965 **** * under artificial conditions. */ if (jstate && !entry) ! usage = USAGE_NON_EXEC_STICK; else usage = USAGE_EXEC(duration); --- 962,970 ---- * under artificial conditions. */ if (jstate && !entry) ! usage = pgss->cur_med_usage; ! else if (jstate && entry) ! usage = 0; else usage = USAGE_EXEC(duration); *************** entry_dealloc(void) *** 1297,1309 **** while ((entry = hash_seq_search(&hash_seq)) != NULL) { entries[i++] = entry; ! entry->counters.usage *= USAGE_DECREASE_FACTOR; } qsort(entries, i, sizeof(pgssEntry *), entry_cmp); nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100); nvictims = Min(nvictims, i); for (i = 0; i < nvictims; i++) { hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL); --- 1302,1321 ---- while ((entry = hash_seq_search(&hash_seq)) != NULL) { entries[i++] = entry; ! ! 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); nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100); nvictims = Min(nvictims, i); + /* Record the median usage */ + pgss->cur_med_usage = entries[i / 2]->counters.usage; + for (i = 0; i < nvictims; i++) { hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);