On Wed, Oct  9, 2013 at 09:52:03AM -0700, Josh Berkus wrote:
> On 10/09/2013 09:30 AM, Stephen Frost wrote:
> >>> I went with shared_buffers because unlike the others, it is a fixed
> >>> > > allocation quantity, while the other are much more variable and harder
> >>> > > to set.  I figured we could keep our 25% estimate of shared_buffers 
> >>> > > and
> >>> > > everything else would fall in line.
> >>> > >
> >> > 
> >> > I understand, but your proposal change a logic to opposite direction. 
> >> > Maybe
> >> > better is wait to new GUC parameter, and then implement this feature, so 
> >> > be
> >> > logical and simply understandable.
> > I disagree- having a better default than what we have now is going to
> > almost certainly be a huge improvement in the vast majority of cases.
> > How we arrive at the default isn't particularly relevant as long as we
> > document it.  Users who end up using the default don't do so because
> > they read the docs and said "oh, yeah, the way they calculated the
> > default makes a lot of sense", then end up using it because they never
> > open the config file, at all.
> 
> FWIW,  I've been using the following calculations as "starting points"
> for work_mem with both clients and students.  In 80-90% of cases, the
> user never adjusts the thresholds again, so I'd say that passes the test
> for a "good enough" setting.

OK, I have developed the attached patch based on feedback.  I took into
account Andrew's concern that pooling might cause use of more work_mem
than you would expect in a typical session, and Robert's legitimate
concern about a destabalizing default for work_mem.  I therefore went
with the shared_buffers/4 idea.  Josh had some interesting calculations
for work_mem, but I didn't think the max value would work well as it
would confuse users and not be properly maintained by us as hardware
grew.  I also think changing those defaults between major releases would
be perhaps destabilizing.  Josh's observation that he rarely sees more
than 3x work_mem in a session helps put an upper limit on memory usage.

I did like Josh's idea about using autovacuum_max_workers for
maintenance_work_mem, though I used the shared_buffers/4 calculation.

Here are the defaults for two configurations;  first, for the 128MB
default shared_buffers:

        test=> SHOW shared_buffers;
         shared_buffers
        ----------------
         128MB
        (1 row)
        
        test=> SHOW work_mem;
         work_mem
        ----------
         1095kB
        (1 row)
        
        test=> SHOW maintenance_work_mem;
         maintenance_work_mem
        ----------------------
         10922kB
        (1 row)

and for shared_buffers of 2GB:

        test=> show shared_buffers;
         shared_buffers
        ----------------
         2GB
        (1 row)
        
        test=> SHOW work_mem;
         work_mem
        ----------
         6010kB
        (1 row)
        
        test=> SHOW maintenance_work_mem ;
         maintenance_work_mem
        ----------------------
         174762kB
        (1 row)


-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + Everyone has their own god. +
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
new file mode 100644
index e8e8e6f..31f1265
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** include 'filename'
*** 1121,1127 ****
         <para>
          Specifies the amount of memory to be used by internal sort operations
          and hash tables before writing to temporary disk files. The value
!         defaults to one megabyte (<literal>1MB</>).
          Note that for a complex query, several sort or hash operations might be
          running in parallel; each operation will be allowed to use as much memory
          as this value specifies before it starts to write data into temporary
--- 1121,1128 ----
         <para>
          Specifies the amount of memory to be used by internal sort operations
          and hash tables before writing to temporary disk files. The value
!         defaults to <varname>shared_buffers</> / 4 /
!         <varname>max_connections</> + 768kB.
          Note that for a complex query, several sort or hash operations might be
          running in parallel; each operation will be allowed to use as much memory
          as this value specifies before it starts to write data into temporary
*************** include 'filename'
*** 1147,1153 ****
          Specifies the maximum amount of memory to be used by maintenance
          operations, such as <command>VACUUM</command>, <command>CREATE
          INDEX</>, and <command>ALTER TABLE ADD FOREIGN KEY</>.  It defaults
!         to 16 megabytes (<literal>16MB</>).  Since only one of these
          operations can be executed at a time by a database session, and
          an installation normally doesn't have many of them running
          concurrently, it's safe to set this value significantly larger
--- 1148,1155 ----
          Specifies the maximum amount of memory to be used by maintenance
          operations, such as <command>VACUUM</command>, <command>CREATE
          INDEX</>, and <command>ALTER TABLE ADD FOREIGN KEY</>.  It defaults
!         to <varname>shared_buffers</> / 4 /
!         <varname>autovacuum_max_workers</>.  Since only one of these
          operations can be executed at a time by a database session, and
          an installation normally doesn't have many of them running
          concurrently, it's safe to set this value significantly larger
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
new file mode 100644
index 33efb3c..68af1dc
*** a/src/backend/utils/init/globals.c
--- b/src/backend/utils/init/globals.c
*************** int			CTimeZone = 0;
*** 98,105 ****
  
  bool		enableFsync = true;
  bool		allowSystemTableMods = false;
! int			work_mem = 1024;
! int			maintenance_work_mem = 16384;
  
  /*
   * Primary determinants of sizes of shared-memory structures.
--- 98,105 ----
  
  bool		enableFsync = true;
  bool		allowSystemTableMods = false;
! int			work_mem = -1;
! int			maintenance_work_mem = -1;
  
  /*
   * Primary determinants of sizes of shared-memory structures.
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
new file mode 100644
index ddbeb34..29b1943
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 117,122 ****
--- 117,125 ----
  #define S_PER_D (60 * 60 * 24)
  #define MS_PER_D (1000 * 60 * 60 * 24)
  
+ /* This is the minimum added for auto-tuning of work_mem */
+ #define WORK_MEM_ADDITION_kB	768
+ 
  /* XXX these should appear in other modules' header files */
  extern bool Log_disconnections;
  extern int	CommitDelay;
*************** static struct config_int ConfigureNamesI
*** 1720,1727 ****
  			GUC_UNIT_KB
  		},
  		&work_mem,
! 		1024, 64, MAX_KILOBYTES,
! 		NULL, NULL, NULL
  	},
  
  	{
--- 1723,1730 ----
  			GUC_UNIT_KB
  		},
  		&work_mem,
! 		-1, -1, MAX_KILOBYTES,
! 		check_work_mem, NULL, NULL
  	},
  
  	{
*************** static struct config_int ConfigureNamesI
*** 1731,1738 ****
  			GUC_UNIT_KB
  		},
  		&maintenance_work_mem,
! 		16384, 1024, MAX_KILOBYTES,
! 		NULL, NULL, NULL
  	},
  
  	/*
--- 1734,1741 ----
  			GUC_UNIT_KB
  		},
  		&maintenance_work_mem,
! 		-1, -1, MAX_KILOBYTES,
! 		check_maintenance_work_mem, NULL, NULL
  	},
  
  	/*
*************** SelectConfigFiles(const char *userDoptio
*** 4239,4245 ****
  	pg_timezone_abbrev_initialize();
  
  	set_default_effective_cache_size();
! 	    
  	/*
  	 * Figure out where pg_hba.conf is, and make sure the path is absolute.
  	 */
--- 4242,4249 ----
  	pg_timezone_abbrev_initialize();
  
  	set_default_effective_cache_size();
! 	set_default_work_mems();
! 
  	/*
  	 * Figure out where pg_hba.conf is, and make sure the path is absolute.
  	 */
*************** show_log_file_mode(void)
*** 8886,8889 ****
--- 8890,8984 ----
  	return buf;
  }
  
+ void
+ set_default_work_mems(void)
+ {
+ 	/*
+ 	 * If the value of work_mem is -1, use the preferred
+ 	 * auto-tune value.
+ 	 */
+ 	if (work_mem == -1)
+ 	{
+ 		char		buf[32];
+ 
+ 		snprintf(buf, sizeof(buf), "%ld", ((NBuffers / 4) * BLCKSZ / 1024L) /
+ 				 MaxConnections + WORK_MEM_ADDITION_kB);
+ 		SetConfigOption("work_mem", buf, PGC_POSTMASTER, PGC_S_OVERRIDE);
+ 	}
+ 	Assert(work_mem > 0);
+ 
+ 	if (maintenance_work_mem == -1)
+ 	{
+ 		char		buf[32];
+ 
+ 		snprintf(buf, sizeof(buf), "%ld", ((NBuffers / 4) * BLCKSZ / 1024L) /
+ 				 autovacuum_max_workers);
+ 		SetConfigOption("maintenance_work_mem", buf, PGC_POSTMASTER, PGC_S_OVERRIDE);
+ 	}
+ 	Assert(maintenance_work_mem > 0);
+ }
+ 
+ /*
+  * GUC check_hook for work_mem
+  */
+ bool
+ check_work_mem(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 later.
+ 		 */
+ 		if (work_mem == -1)
+ 			return true;
+ 
+ 		/* Otherwise, substitute the auto-tune value */
+ 		*newval = ((NBuffers / 4) * BLCKSZ / 1024L) / MaxConnections +
+ 				   WORK_MEM_ADDITION_kB;
+ 	}
+ 
+ 	/* set minimum?  check maximum? */
+ 	if (*newval < 64)
+ 		*newval = 64;
+ 	if (*newval > MAX_KILOBYTES)
+ 		*newval = MAX_KILOBYTES;
+ 
+ 	return true;
+ }
+ 
+ /*
+  * GUC check_hook for maintenance_work_mem
+  */
+ bool
+ check_maintenance_work_mem(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 later.
+ 		 */
+ 		if (maintenance_work_mem == -1)
+ 			return true;
+ 
+ 		/* Otherwise, substitute the auto-tune value */
+ 		*newval = ((NBuffers / 4) * BLCKSZ / 1024L) / autovacuum_max_workers;
+ 	}
+ 
+ 	/* set minimum?  check maximum? */
+ 	if (*newval < 1024)
+ 		*newval = 1024;
+ 	if (*newval > MAX_KILOBYTES)
+ 		*newval = MAX_KILOBYTES;
+ 
+ 	return true;
+ }
+ 
  #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
new file mode 100644
index 70221f4..a8da95b
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 120,127 ****
  # per transaction slot, plus lock space (see max_locks_per_transaction).
  # It is not advisable to set max_prepared_transactions nonzero unless you
  # actively intend to use prepared transactions.
! #work_mem = 1MB				# min 64kB
! #maintenance_work_mem = 16MB		# min 1MB
  #max_stack_depth = 2MB			# min 100kB
  
  # - Disk -
--- 120,127 ----
  # per transaction slot, plus lock space (see max_locks_per_transaction).
  # It is not advisable to set max_prepared_transactions nonzero unless you
  # actively intend to use prepared transactions.
! #work_mem = -1				# min 64kB
! #maintenance_work_mem = -1		# min 1MB
  #max_stack_depth = 2MB			# min 100kB
  
  # - Disk -
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
new file mode 100644
index 3e981b3..f696eed
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern void assign_search_path(const cha
*** 388,393 ****
--- 388,396 ----
  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 bool check_work_mem(int *newval, void **extra, GucSource source);
+ extern bool check_maintenance_work_mem(int *newval, void **extra, GucSource source);
+ extern void set_default_work_mems(void);
  extern void assign_xlog_sync_method(int new_sync_method, void *extra);
  
  #endif   /* GUC_H */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to