From ee1e5662d8d8330726eaef7d3110cb7add24d058 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Tue, 8 Oct 2013 12:12:24 -0400 Subject: [PATCH] Auto-tune effective_cache size to be 4x shared buffers --- doc/src/sgml/config.sgml | 22 ++++++++---- src/backend/optimizer/path/costsize.c | 50 +++++++++++++++++++++++++-- src/backend/postmaster/postmaster.c | 3 ++ src/backend/utils/misc/guc.c | 4 +-- src/include/optimizer/cost.h | 2 +- src/include/utils/guc.h | 2 ++ src/test/regress/expected/join.out | 1 + src/test/regress/sql/join.sql | 2 ++ 8 files changed, 75 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 697cf40137..116acd7eca 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2758,7 +2758,7 @@ include 'filename' Random access to mechanical disk storage is normally much more expensive - than four-times sequential access. However, a lower default is used + than four times sequential access. However, a lower default is used (4.0) because the majority of random accesses to disk, such as indexed reads, are assumed to be in cache. The default value can be thought of as modeling random access as 40 times slower than sequential, while @@ -2841,9 +2841,17 @@ include 'filename' Sets the planner's assumption about the effective size of the - disk cache that is available to a single query. This is - factored into estimates of the cost of using an index; a - higher value makes it more likely index scans will be used, a + disk cache that is available to a single query. The default + setting of -1 selects a size equal to four times the size of , but not less than the size of one + shared buffer page, typically 8kB. This value + can be set manually if the automatic choice is too large or too + small. + + + + This value is factored into estimates of the cost of using an index; + a higher value makes it more likely index scans will be used, a lower value makes it more likely sequential scans will be used. When setting this parameter you should consider both PostgreSQL's shared buffers and the @@ -2855,8 +2863,10 @@ include 'filename' memory allocated by PostgreSQL, nor does it reserve kernel disk cache; it is used only for estimation purposes. The system also does not assume data remains in - the disk cache between queries. The default is 128 megabytes - (128MB). + the disk cache between queries. The auto-tuning + selected by the default setting of -1 should give reasonable + results if this database cluster is can utilize most of the memory + on this server. diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 0caac75ac5..82c66f76ca 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -87,6 +87,7 @@ #include "optimizer/planmain.h" #include "optimizer/restrictinfo.h" #include "parser/parsetree.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" #include "utils/spccache.h" @@ -95,14 +96,13 @@ #define LOG2(x) (log(x) / 0.693147180559945) - double seq_page_cost = DEFAULT_SEQ_PAGE_COST; double random_page_cost = DEFAULT_RANDOM_PAGE_COST; double cpu_tuple_cost = DEFAULT_CPU_TUPLE_COST; double cpu_index_tuple_cost = DEFAULT_CPU_INDEX_TUPLE_COST; double cpu_operator_cost = DEFAULT_CPU_OPERATOR_COST; -int effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE; +int effective_cache_size = -1; Cost disable_cost = 1.0e10; @@ -456,6 +456,52 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count) path->path.total_cost = startup_cost + run_cost; } +void +set_default_effective_cache_size(void) +{ + /* + * If the value of effective_cache_size is -1, use the preferred + * auto-tune value. + */ + if (effective_cache_size == -1) + { + char buf[32]; + + snprintf(buf, sizeof(buf), "%d", NBuffers * DEFAULT_EFFECTIVE_CACHE_SIZE_MULTI); + SetConfigOption("effective_cache_size", buf, PGC_POSTMASTER, PGC_S_OVERRIDE); + } + Assert(effective_cache_size > 0); +} + +/* + * GUC check_hook for effective_cache_size + */ +bool +check_effective_cache_size(int *newval, void **extra, GucSource source) +{ + /* + * -1 indicates a request for auto-tune. + */ + if (*newval == -1) + { + /* + * If we haven't yet changed the boot_val default of -1, just let it + * be. We'll fix it in index_pages_fetched + */ + if (effective_cache_size == -1) + return true; + + /* Otherwise, substitute the auto-tune value */ + *newval = NBuffers * DEFAULT_EFFECTIVE_CACHE_SIZE_MULTI; + } + + /* set minimum? */ + if (*newval < 1) + *newval = 1; + + return true; +} + /* * index_pages_fetched * Estimate the number of pages actually fetched after accounting for diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 9f721b7651..c4b54d12cb 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -118,6 +118,7 @@ #include "utils/builtins.h" #include "utils/datetime.h" #include "utils/dynamic_loader.h" +#include "utils/guc.h" #include "utils/memutils.h" #include "utils/ps_status.h" #include "utils/timeout.h" @@ -4475,6 +4476,8 @@ SubPostmasterMain(int argc, char *argv[]) memset(&port, 0, sizeof(Port)); read_backend_variables(argv[2], &port); + set_default_effective_cache_size(); + /* * Set reference point for stack-depth checking */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index d9a06b4d88..833f34b1ee 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2410,8 +2410,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS, }, &effective_cache_size, - DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX, - NULL, NULL, NULL + -1, -1, INT_MAX, + check_effective_cache_size, NULL, NULL }, { diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index a052944d10..444ab74044 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -27,7 +27,7 @@ #define DEFAULT_CPU_INDEX_TUPLE_COST 0.005 #define DEFAULT_CPU_OPERATOR_COST 0.0025 -#define DEFAULT_EFFECTIVE_CACHE_SIZE 16384 /* measured in pages */ +#define DEFAULT_EFFECTIVE_CACHE_SIZE_MULTI 4 typedef enum { diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 89ee40c334..3e981b3e94 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -386,6 +386,8 @@ extern void assign_search_path(const char *newval, void *extra); /* in access/transam/xlog.c */ extern bool check_wal_buffers(int *newval, void **extra, GucSource source); +extern bool check_effective_cache_size(int *newval, void **extra, GucSource source); +extern void set_default_effective_cache_size(void); extern void assign_xlog_sync_method(int new_sync_method, void *extra); #endif /* GUC_H */ diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index c94ac614af..d46ff26d82 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -2713,6 +2713,7 @@ where thousand = (q1 + q2); -- -- test placement of movable quals in a parameterized join tree -- +set effective_cache_size = '128MB'; explain (costs off) select * from tenk1 t1 left join (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2) diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 351400f2da..1a4dc03d18 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -711,6 +711,8 @@ where thousand = (q1 + q2); -- test placement of movable quals in a parameterized join tree -- +set effective_cache_size = '128MB'; + explain (costs off) select * from tenk1 t1 left join (tenk1 t2 join tenk1 t3 on t2.thousand = t3.unique2)