# Re: [HACKERS] gaussian distribution pgbench

```Hi Heikki-san,

(2014/03/17 14:39), KONDO Mitsumasa wrote:
```
```(2014/03/15 15:53), Fabien COELHO wrote:
```
```
Hello Heikki,

```
```A couple of comments:

* There should be an explicit "\setrandom ... uniform" option too, even though
you get that implicitly if you don't specify the distribution
```
```Fix. We can use "\setrandom val min max uniform" without error messages.

```
```* What exactly does the "threshold" mean? The docs informally explain that "the
larger the thresold, the more frequent values close to the middle of the
interval are drawn", but that's pretty vague.
```
```
There are explanations and computations as comments in the code. If it is about
the documentation, I'm not sure that a very precise mathematical definition will
help a lot of people, and might rather hinder understanding, so the doc focuses
```
```Add more detail information in the document. Is it OK? Please confirm it.

```
```* Does min and max really make sense for gaussian and exponential
distributions? For gaussian, I would expect mean and standard deviation as the
parameters, not min/max/threshold.
```
```
Yes... and no:-) The aim is to draw an integer primary key from a table, so it
must be in a specified range. This is approximated by drawing a double value
with
the expected distribution (gaussian or exponential) and project it carefully
onto
integers. If it is out of range, there is a loop and another value is drawn. The
minimal threshold constraint (2.0) ensures that the probability of looping is
low.
```
```It make sense. Please see the attached picutre in last day.

```
```* How about setting the variable as a float instead of integer? Would seem more
natural to me. At least as an option.
```
```
Which variable? The values set by setrandom are mostly used for primary keys. We
really want integers in a range.
```
```Oh, I see. He said about documents.
```
```The document was mistaken.
Threshold parameter must be double and fix the document.

```
By the way, you seem to want to remove --gaussian=NUM and --exponential=NUM command options. Can you tell me the objective reason? I think pgbench is the
```benchmark test on PostgreSQL and default benchmark is TPC-B-like benchmark.
It is written in documents, and default benchmark wasn't changed by my patch.
So we need not remove command options, and they are one of the variety of
benchmark options. Maybe you have something misunderstanding about my patch...

Regards,
--
Mitsumasa KONDO
NTT Open Source Software Center
```
```*** a/contrib/pgbench/pgbench.c
--- b/contrib/pgbench/pgbench.c
***************
--- 98,106 ----
#define LOG_STEP_SECONDS	5	/* seconds between log messages */
#define DEFAULT_NXACTS	10		/* default nxacts */

+ #define MIN_GAUSSIAN_THRESHOLD		2.0	/* minimum threshold for gauss */
+ #define MIN_EXPONENTIAL_THRESHOLD	2.0	/* minimum threshold for exp */
+
int			nxacts = 0;			/* number of transactions per client */
int			duration = 0;		/* duration in seconds */

***************
*** 169,174 **** bool		is_connect;			/* establish connection for each transaction */
--- 172,185 ----
bool		is_latencies;		/* report per-command latencies */
int			main_pid;			/* main process id used in log filename */

+ /* gaussian distribution tests: */
+ double		stdev_threshold;   /* standard deviation threshold */
+ bool        use_gaussian = false;
+
+ /* exponential distribution tests: */
+ double		exp_threshold;   /* threshold for exponential */
+ bool		use_exponential = false;
+
char	   *pghost = "";
char	   *pgport = "";
***************
*** 330,335 **** static char *select_only = {
--- 341,428 ----
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
};

+ /* --exponential case */
+ static char *exponential_tpc_b = {
+ 	"\\set nbranches " CppAsString2(nbranches) " * :scale\n"
+ 	"\\set ntellers " CppAsString2(ntellers) " * :scale\n"
+ 	"\\set naccounts " CppAsString2(naccounts) " * :scale\n"
+ 	"\\setrandom aid 1 :naccounts exponential :exp_threshold\n"
+ 	"\\setrandom bid 1 :nbranches\n"
+ 	"\\setrandom tid 1 :ntellers\n"
+ 	"\\setrandom delta -5000 5000\n"
+ 	"BEGIN;\n"
+ 	"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
+ 	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ 	"UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
+ 	"UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
+ 	"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+ 	"END;\n"
+ };
+
+ /* --exponential with -N case */
+ static char *exponential_simple_update = {
+ 	"\\set nbranches " CppAsString2(nbranches) " * :scale\n"
+ 	"\\set ntellers " CppAsString2(ntellers) " * :scale\n"
+ 	"\\set naccounts " CppAsString2(naccounts) " * :scale\n"
+ 	"\\setrandom aid 1 :naccounts exponential :exp_threshold\n"
+ 	"\\setrandom bid 1 :nbranches\n"
+ 	"\\setrandom tid 1 :ntellers\n"
+ 	"\\setrandom delta -5000 5000\n"
+ 	"BEGIN;\n"
+ 	"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
+ 	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ 	"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+ 	"END;\n"
+ };
+
+ /* --exponential with -S case */
+ static char *exponential_select_only = {
+ 	"\\set naccounts " CppAsString2(naccounts) " * :scale\n"
+ 	"\\setrandom aid 1 :naccounts exponential :exp_threshold\n"
+ 	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ };
+
+ /* --gaussian case */
+ static char *gaussian_tpc_b = {
+ 	"\\set nbranches " CppAsString2(nbranches) " * :scale\n"
+ 	"\\set ntellers " CppAsString2(ntellers) " * :scale\n"
+ 	"\\set naccounts " CppAsString2(naccounts) " * :scale\n"
+ 	"\\setrandom aid 1 :naccounts gaussian :stdev_threshold\n"
+ 	"\\setrandom bid 1 :nbranches\n"
+ 	"\\setrandom tid 1 :ntellers\n"
+ 	"\\setrandom delta -5000 5000\n"
+ 	"BEGIN;\n"
+ 	"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
+ 	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ 	"UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
+ 	"UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
+ 	"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+ 	"END;\n"
+ };
+
+ /* --gaussian with -N case */
+ static char *gaussian_simple_update = {
+ 	"\\set nbranches " CppAsString2(nbranches) " * :scale\n"
+ 	"\\set ntellers " CppAsString2(ntellers) " * :scale\n"
+ 	"\\set naccounts " CppAsString2(naccounts) " * :scale\n"
+ 	"\\setrandom aid 1 :naccounts gaussian :stdev_threshold\n"
+ 	"\\setrandom bid 1 :nbranches\n"
+ 	"\\setrandom tid 1 :ntellers\n"
+ 	"\\setrandom delta -5000 5000\n"
+ 	"BEGIN;\n"
+ 	"UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
+ 	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ 	"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
+ 	"END;\n"
+ };
+
+ /* --gaussian with -S case */
+ static char *gaussian_select_only = {
+ 	"\\set naccounts " CppAsString2(naccounts) " * :scale\n"
+ 	"\\setrandom aid 1 :naccounts gaussian :stdev_threshold\n"
+ 	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
+ };
+
/* Function prototypes */
static void setalarm(int seconds);
***************
*** 373,378 **** usage(void)
--- 466,473 ----
"  -v, --vacuum-all         vacuum all four standard tables before tests\n"
"  --aggregate-interval=NUM aggregate data over NUM seconds\n"
"  --sampling-rate=NUM      fraction of transactions to log (e.g. 0.01 for 1%%)\n"
+ 		   "  --exponential=NUM        exponential distribution with NUM threshold parameter\n"
+ 		   "  --gaussian=NUM           gaussian distribution with NUM threshold parameter\n"
"\nCommon options:\n"
"  -d, --debug              print debugging output\n"
"  -h, --host=HOSTNAME      database server host or socket directory\n"
***************
*** 469,474 **** getrand(TState *thread, int64 min, int64 max)
--- 564,642 ----
return min + (int64) ((max - min + 1) * pg_erand48(thread->random_state));
}

+ /* random number generator: exponential distribution from min to max inclusive */
+ static int64
+ getExponentialrand(TState *thread, int64 min, int64 max, double exp_threshold)
+ {
+ 	double		rand;
+
+ 	/*
+ 	 * Get user specified random number in this loop. This loop is executed until
+ 	 * the number in the expected range. As the minimum threshold is 2.0, the
+ 	 * probability of a retry is at worst 13.5% as - ln(0.135) ~ 2.0 ;
+ 	 * For a 5.0 threshold, it is about e^{-5} ~ 0.7%.
+ 	 */
+ 	do
+ 	{
+ 		/* as pg_erand48 is in [0, 1), uniform is in (0, 1] */
+ 		double uniform = 1.0 - pg_erand48(thread->random_state);
+ 		/* rand is in [0 LARGE) */
+ 		rand = - log(uniform);
+ 	} while (rand >= exp_threshold);
+
+ 	/* rand in [0, exp_threshold), normalized to [0,1) */
+ 	rand /= exp_threshold;
+
+ 	/* return int64 random number within between min and max */
+ 	return min + (int64)((max - min + 1) * rand);
+ }
+
+ /* random number generator: gaussian distribution from min to max inclusive */
+ static int64
+ getGaussianrand(TState *thread, int64 min, int64 max, double stdev_threshold)
+ {
+ 	double		stdev;
+ 	double		rand;
+
+ 	/*
+ 	 * Get user specified random number from this loop, with
+ 	 * -stdev_threshold < stdev <= stdev_threshold
+ 	 *
+ 	 * This loop is executed until the number is in the expected range.
+ 	 *
+ 	 * As the minimum threshold is 2.0, the probability of looping is low:
+ 	 * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the average
+ 	 * sinus multiplier as 2/pi, we have a 8.6% looping probability in the
+ 	 * worst case. For a 5.0 threshold value, the looping proability
+ 	 * is about e^{-5} * 2 / pi ~ 0.43%.
+ 	 */
+ 	do
+ 	{
+ 		/*
+ 		 * pg_erand48 generates [0,1), but for the basic version of the
+ 		 * Box-Muller transform the two uniformly distributed random numbers
+ 		 * are expected in (0, 1] (see http://en.wikipedia.org/wiki/Box_muller)
+ 		 */
+ 		double rand1 = 1.0 - pg_erand48(thread->random_state);
+ 		double rand2 = 1.0 - pg_erand48(thread->random_state);
+
+ 		/* Box-Muller basic form transform */
+ 		double var_sqrt = sqrt(-2.0 * log(rand1));
+ 		stdev = var_sqrt * sin(2.0 * M_PI * rand2);
+
+ 		/* we may try with cos, but there may be a bias induced if the previous
+ 		 * value fails the test? To be on the safe side, let us try over.
+ 		 */
+ 	}
+ 	while (stdev < -stdev_threshold || stdev >= stdev_threshold);
+
+ 	/* stdev is in [-threshold, threshold), normalization to [0,1) */
+ 	rand = (stdev + stdev_threshold) / (stdev_threshold * 2.0);
+
+ 	/* return int64 random number within between min and max */
+ 	return min + (int64)((max - min + 1) * rand);
+ }
+
/* call PQexec() and exit() on failure */
static void
executeStatement(PGconn *con, const char *sql)
***************
*** 1312,1317 **** top:
--- 1480,1486 ----
char	   *var;
int64		min,
max;
+ 			double		threshold = 0;
char		res[64];

if (*argv[2] == ':')
***************
*** 1357,1367 **** top:
}

/*
! 			 * getrand() needs to be able to subtract max from min and add one
! 			 * to the result without overflowing.  Since we know max > min, we
! 			 * can detect overflow just by checking for a negative result. But
! 			 * we must check both that the subtraction doesn't overflow, and
! 			 * that adding one to the result doesn't overflow either.
*/
if (max - min < 0 || (max - min) + 1 < 0)
{
--- 1526,1536 ----
}

/*
! 			 * Generate random number functions need to be able to subtract
! 			 * max from min and add one to the result without overflowing.
! 			 * Since we know max > min, we can detect overflow just by checking
! 			 * for a negative result. But we must check both that the subtraction
! 			 * doesn't overflow, and that adding one to the result doesn't overflow either.
*/
if (max - min < 0 || (max - min) + 1 < 0)
{
***************
*** 1370,1379 **** top:
return true;
}

#ifdef DEBUG
! 			printf("min: " INT64_FORMAT " max: " INT64_FORMAT " random: " INT64_FORMAT "\n", min, max, getrand(thread, min, max));
#endif
! 			snprintf(res, sizeof(res), INT64_FORMAT, getrand(thread, min, max));

if (!putVariable(st, argv[0], argv[1], res))
{
--- 1539,1601 ----
return true;
}

+ 			if (argc == 4) /* uniform */
+ 			{
+ #ifdef DEBUG
+ 				printf("min: " INT64_FORMAT " max: " INT64_FORMAT " random: " INT64_FORMAT "\n", min, max, getrand(thread, min, max));
+ #endif
+ 				snprintf(res, sizeof(res), INT64_FORMAT, getrand(thread, min, max));
+ 			}
+ 			else if ((pg_strcasecmp(argv[4], "gaussian") == 0) ||
+ 				 (pg_strcasecmp(argv[4], "exponential") == 0))
+ 			{
+ 				if (*argv[5] == ':')
+ 				{
+ 					if ((var = getVariable(st, argv[5] + 1)) == NULL)
+ 					{
+ 						fprintf(stderr, "%s: invalid threshold number %s\n", argv[0], argv[5]);
+ 						st->ecnt++;
+ 						return true;
+ 					}
+ 					threshold = strtod(var, NULL);
+ 				}
+ 				else
+ 					threshold = strtod(argv[5], NULL);
+
+ 				if (pg_strcasecmp(argv[4], "gaussian") == 0)
+ 				{
+ 					if (threshold < MIN_GAUSSIAN_THRESHOLD)
+ 					{
+ 						fprintf(stderr, "%s: gaussian threshold must be more than %f\n,", argv[5], MIN_GAUSSIAN_THRESHOLD);
+ 						st->ecnt++;
+ 						return true;
+ 					}
#ifdef DEBUG
! 					printf("min: " INT64_FORMAT " max: " INT64_FORMAT " random: " INT64_FORMAT "\n", min, max, getGaussianrand(thread, min, max, threshold));
#endif
! 					snprintf(res, sizeof(res), INT64_FORMAT, getGaussianrand(thread, min, max, threshold));
! 				}
! 				else if (pg_strcasecmp(argv[4], "exponential") == 0)
! 				{
! 					if (threshold < MIN_EXPONENTIAL_THRESHOLD)
! 					{
! 						fprintf(stderr, "%s: exponential threshold must be more than %f\n,", argv[5], MIN_EXPONENTIAL_THRESHOLD);
! 						st->ecnt++;
! 						return true;
! 					}
! #ifdef DEBUG
! 					printf("min: " INT64_FORMAT " max: " INT64_FORMAT " random: " INT64_FORMAT "\n", min, max, getExponentialrand(thread, min, max, threshold));
! #endif
! 					snprintf(res, sizeof(res), INT64_FORMAT, getExponentialrand(thread, min, max, threshold));
! 				}
! 			}
! 			else /* uniform with extra arguments */
! 			{
! #ifdef DEBUG
! 				printf("min: " INT64_FORMAT " max: " INT64_FORMAT " random: " INT64_FORMAT "\n", min, max, getrand(thread, min, max));
! #endif
! 				snprintf(res, sizeof(res), INT64_FORMAT, getrand(thread, min, max));
! 			}

if (!putVariable(st, argv[0], argv[1], res))
{
***************
*** 1903,1911 **** process_commands(char *buf)
exit(1);
}

! 			for (j = 4; j < my_commands->argc; j++)
! 				fprintf(stderr, "%s: extra argument \"%s\" ignored\n",
! 						my_commands->argv[0], my_commands->argv[j]);
}
else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
{
--- 2125,2158 ----
exit(1);
}

! 			if (my_commands->argc == 4 ) /* uniform */
! 			{
! 				/* nothing to do */
! 			}
! 			else if ((pg_strcasecmp(my_commands->argv[4], "gaussian") == 0) ||
! 				 (pg_strcasecmp(my_commands->argv[4], "exponential") == 0))
! 			{
! 				if (my_commands->argc < 6)
! 				{
! 					fprintf(stderr, "%s(%s): missing argument\n", my_commands->argv[0], my_commands->argv[4]);
! 					exit(1);
! 				}
!
! 				for (j = 6; j < my_commands->argc; j++)
! 					fprintf(stderr, "%s(%s): extra argument \"%s\" ignored\n",
! 							my_commands->argv[0], my_commands->argv[4], my_commands->argv[j]);
! 			}
! 			else /* uniform with extra argument */
! 			{
! 				int arg_pos = 4;
!
! 				if (pg_strcasecmp(my_commands->argv[4], "uniform") == 0)
! 					arg_pos++;
!
! 				for (j = arg_pos; j < my_commands->argc; j++)
! 					fprintf(stderr, "%s(uniform): extra argument \"%s\" ignored\n",
! 							my_commands->argv[0], my_commands->argv[j]);
! 			}
}
else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
{
***************
*** 2180,2195 **** printResults(int ttype, int normal_xacts, int nclients,

if (ttype == 0)
! 		s = "TPC-B (sort of)";
else if (ttype == 2)
! 		s = "Update only pgbench_accounts";
else if (ttype == 1)
! 		s = "SELECT only";
else
s = "Custom query";

printf("transaction type: %s\n", s);
printf("scaling factor: %d\n", scale);
printf("query mode: %s\n", QUERYMODE[querymode]);
printf("number of clients: %d\n", nclients);
--- 2427,2483 ----

if (ttype == 0)
! 	{
! 		if (use_gaussian)
! 			s = "Gaussian distribution TPC-B (sort of)";
! 		else if (use_exponential)
! 			s = "Exponential distribution TPC-B (sort of)";
! 		else
! 			s = "TPC-B (sort of)";
! 	}
else if (ttype == 2)
! 	{
! 		if (use_gaussian)
! 			s = "Gaussian distribution update only pgbench_accounts";
! 		else if (use_exponential)
! 			s = "Exponential distribution update only pgbench_accounts";
! 		else
! 			s = "Update only pgbench_accounts";
! 	}
else if (ttype == 1)
! 	{
! 		if (use_gaussian)
! 			s = "Gaussian distribution SELECT only";
! 		else if (use_exponential)
! 			s = "Exponential distribution SELECT only";
! 		else
! 			s = "SELECT only";
! 	}
else
s = "Custom query";

printf("transaction type: %s\n", s);
printf("scaling factor: %d\n", scale);
+
+ 	/* output in gaussian distribution benchmark */
+ 	if (use_gaussian)
+ 	{
+ 		printf("standard deviation threshold: %.5f\n", stdev_threshold);
+ 		printf("access probability of top 20%%, 10%% and 5%% records: %.5f %.5f %.5f\n",
+ 			(double) ((erf (stdev_threshold * 0.2 / sqrt(2.0))) / (erf (stdev_threshold / sqrt(2.0)))),
+ 			(double) ((erf (stdev_threshold * 0.1 / sqrt(2.0))) / (erf (stdev_threshold / sqrt(2.0)))),
+ 			(double) ((erf (stdev_threshold * 0.05 / sqrt(2.0))) / (erf (stdev_threshold / sqrt(2.0)))));
+ 	}
+ 	/* output in exponential distribution benchmark */
+ 	else if (use_exponential)
+ 	{
+ 		printf("exponential threshold: %.5f\n", exp_threshold);
+ 		printf("access probability of top 20%%, 10%% and 5%% records: %.5f %.5f %.5f\n",
+ 			(double) (-exp(-exp_threshold * 0.2) + 1),
+ 			(double) (-exp(-exp_threshold * 0.1) + 1),
+ 			(double) (-exp(-exp_threshold * 0.05) + 1));
+ 	}
+
printf("query mode: %s\n", QUERYMODE[querymode]);
printf("number of clients: %d\n", nclients);
***************
*** 2319,2324 **** main(int argc, char **argv)
--- 2607,2614 ----
{"unlogged-tables", no_argument, &unlogged_tables, 1},
{"sampling-rate", required_argument, NULL, 4},
{"aggregate-interval", required_argument, NULL, 5},
+ 		{"gaussian", required_argument, NULL, 6},
+ 		{"exponential", required_argument, NULL, 7},
{"rate", required_argument, NULL, 'R'},
{NULL, 0, NULL, 0}
};
***************
*** 2598,2603 **** main(int argc, char **argv)
--- 2888,2913 ----
}
#endif
break;
+ 			case 6:
+ 				use_gaussian = true;
+ 				stdev_threshold = atof(optarg);
+ 				if(stdev_threshold < MIN_GAUSSIAN_THRESHOLD)
+ 				{
+ 					fprintf(stderr, "--gaussian=NUM must be more than %f: %f\n",
+ 							MIN_GAUSSIAN_THRESHOLD, stdev_threshold);
+ 					exit(1);
+ 				}
+ 				break;
+ 			case 7:
+ 				use_exponential = true;
+ 				exp_threshold = atof(optarg);
+ 				if(exp_threshold < MIN_EXPONENTIAL_THRESHOLD)
+ 				{
+ 					fprintf(stderr, "--exponential=NUM must be more than %f: %f\n",
+ 							MIN_EXPONENTIAL_THRESHOLD, exp_threshold);
+ 					exit(1);
+ 				}
+ 				break;
default:
exit(1);
***************
*** 2795,2800 **** main(int argc, char **argv)
--- 3105,3132 ----
}
}

+ 	/* set :stdev_threshold variable */
+ 	if(getVariable(&state[0], "stdev_threshold") == NULL)
+ 	{
+ 		snprintf(val, sizeof(val), "%lf", stdev_threshold);
+ 		for (i = 0; i < nclients; i++)
+ 		{
+ 			if (!putVariable(&state[i], "startup", "stdev_threshold", val))
+ 				exit(1);
+ 		}
+ 	}
+
+ 	/* set :exp_threshold variable */
+ 	if(getVariable(&state[0], "exp_threshold") == NULL)
+ 	{
+ 		snprintf(val, sizeof(val), "%lf", exp_threshold);
+ 		for (i = 0; i < nclients; i++)
+ 		{
+ 			if (!putVariable(&state[i], "startup", "exp_threshold", val))
+ 				exit(1);
+ 		}
+ 	}
+
if (!is_no_vacuum)
{
fprintf(stderr, "starting vacuum...");
***************
*** 2820,2836 **** main(int argc, char **argv)
switch (ttype)
{
case 0:
! 			sql_files[0] = process_builtin(tpc_b);
num_files = 1;
break;

case 1:
! 			sql_files[0] = process_builtin(select_only);
num_files = 1;
break;

case 2:
! 			sql_files[0] = process_builtin(simple_update);
num_files = 1;
break;

--- 3152,3183 ----
switch (ttype)
{
case 0:
! 			if (use_gaussian)
! 				sql_files[0] = process_builtin(gaussian_tpc_b);
! 			else if (use_exponential)
! 				sql_files[0] = process_builtin(exponential_tpc_b);
! 			else
! 				sql_files[0] = process_builtin(tpc_b);
num_files = 1;
break;

case 1:
! 			if (use_gaussian)
! 				sql_files[0] = process_builtin(gaussian_select_only);
! 			else if (use_exponential)
! 				sql_files[0] = process_builtin(exponential_select_only);
! 			else
! 				sql_files[0] = process_builtin(select_only);
num_files = 1;
break;

case 2:
! 			if (use_gaussian)
! 				sql_files[0] = process_builtin(gaussian_simple_update);
! 			else if (use_exponential)
! 				sql_files[0] = process_builtin(exponential_simple_update);
! 			else
! 				sql_files[0] = process_builtin(simple_update);
num_files = 1;
break;

*** a/doc/src/sgml/pgbench.sgml
--- b/doc/src/sgml/pgbench.sgml
***************
*** 307,312 **** pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
--- 307,329 ----
</varlistentry>

<varlistentry>
+       <term><option>--exponential</option><replaceable>threshold</></term>
+       <listitem>
+        <para>
+          Run exponential distribution pgbench test using threshold parameter.
+          This threshold controls the distribution of access frequency on the
+          <structname>pgbench_accounts</> table.
+          The larger the threshold, the records closed to the beginning
+          of pgbench_accounts table become more access frequency. The smaller
+          the threshold, the smoother the access pattern distribution.
+          The threshold must be more than 2 for client performance.
+          When set, this option applies to all test variants
+          (<option>-N</> for skipping updates, or <option>-S</> for selects).
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
<term><option>-f</option> <replaceable>filename</></term>
<term><option>--file=</option><replaceable>filename</></term>
<listitem>
***************
*** 320,325 **** pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
--- 337,362 ----
</varlistentry>

<varlistentry>
+       <term><option>--gaussian</option><replaceable>threshold</></term>
+       <listitem>
+        <para>
+          Run gaussian distribution pgbench test using threshold parameter.
+          This threshold controls the distribution of access frequency on the
+          <structname>pgbench_accounts</> table.
+          The larger the threshold, the records in the center of values in the table
+          become more access frequency and pointed, and the less frequent accessed
+          values close to the beginning and end of pgbench_accounts table become
+          more less access frequency. Which means that distribution of frequent
+          access range becomes more narrower. The smaller the threshold, the smoother
+          the access pattern distribution. The deviation threshold
+          must be more than 2, for client performance. When set, this option
+          applies to all test variants (<option>-N</> for skipping updates,
+          or <option>-S</> for selects).
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
<listitem>
***************
*** 748,755 **** pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>

<varlistentry>
<term>
!      <literal>\setrandom <replaceable>varname</> <replaceable>min</> <replaceable>max</></literal>
!     </term>

<listitem>
<para>
--- 785,792 ----

<varlistentry>
<term>
!      <literal>\setrandom <replaceable>varname</> <replaceable>min</> <replaceable>max</> [ uniform | [ { gaussian | exponential } <replaceable>threshold</> ] ]</literal>
!      </term>

<listitem>
<para>
***************
*** 757,769 **** pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
between the limits <replaceable>min</> and <replaceable>max</> inclusive.
Each limit can be either an integer constant or a
<literal>:</><replaceable>variablename</> reference to a variable
!       having an integer value.
</para>

<para>
Example:
<programlisting>
! \setrandom aid 1 :naccounts
</programlisting></para>
</listitem>
</varlistentry>
--- 794,834 ----
between the limits <replaceable>min</> and <replaceable>max</> inclusive.
Each limit can be either an integer constant or a
<literal>:</><replaceable>variablename</> reference to a variable
!       having an integer value. Default random distribution is uniform.
!      </para>
!
!      <para>
!       Sets gaussian or exponential with threshold double value,
!       you can get gaussian or exponential random in integer value between
!       <replaceable>min</> and <replaceable>max</> bounds inclusive.
!       The threshold controls the distribution pattern. Without these options,
!       you can get uniform random in interger value between <replaceable>min</>
!       and <replaceable>max</> bounds inclusive.
!      </para>
!
!      <para>
!       In gaussian option, the larger the threshold, the more frequent accessed
!       values close to the middle of the interval become more access frequency
!       and are pointed, and the less frequent accessed values close to the
!       <replaceable>min</> and <replaceable>max</> become more less access
!       frequency. Which means that distribution of frequent access range becomes
!       more narrower. The smaller the threshold, the smoother the access pattern
!       distribution. The minimum threshold is 2.0, for client performance.
!      </para>
!
!      <para>
!       In exponential option, the threshold controls the distribution
!       pattern: the larger the threshold, the values close to
!       <replaceable>min</> become more access frequency, and the frequent
!       accessed values close to <replacebble>max</> become less access frequency.
!       The smaller the threshold, the smoother the access pattern distribution.
!       The minimum threshold is 2.0, for client performance.
</para>

<para>
Example:
<programlisting>
! \setrandom aid 1 :naccounts gaussian 5
</programlisting></para>
</listitem>
</varlistentry>
```
```--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
```