Various pgbench enhancements. Patch contributed by ITAGAKI Takahiro.

Also tweak README.pgbench/README.pgbench_jis:
  Remove history after pgbench was added to PostgreSQL contrib module.
  Those info was not only redundant since it has already been in CVS
  log, but also incomplete.
--------------------------------------------------------------------------
The attached is a patch to optimize contrib/pgbench using new 8.3 features.

- Use DROP IF EXISTS to suppress errors for initial loadings.
- Use a combination of TRUNCATE and COPY to reduce WAL on creating
  the accounts table.

Also, there are some cosmetic changes.

- Change the output of -v option from "starting full vacuum..."
  to "starting vacuum accounts..." in reflection of the fact.
- Shape duplicated error checks into executeStatement().


There is a big performance win in "COPY with no WAL" feature.
Thanks for the efforts!
--------------------------------------------------------------------------
This commit is contained in:
Tatsuo Ishii 2007-04-06 08:49:44 +00:00
parent 37a609b27f
commit 7e96269a82
3 changed files with 75 additions and 254 deletions

View File

@ -1,4 +1,6 @@
pgbench README 2006/10/21 Tatsuo Ishii
$PostgreSQL: pgsql/contrib/pgbench/README.pgbench,v 1.16 2007/04/06 08:49:44 ishii Exp $
pgbench README
o What is pgbench?
@ -233,54 +235,7 @@ o License?
Basically it is same as BSD license. See pgbench.c for more details.
o History
2006/10/21
* more fix with handling default scaling factor in the default
scenarios
2006/09/14
* change "tps" to "scale" to avoid confusion
* fix bug with handling default scaling factor in the default
scenarios
2006/07/26
* New features contributed by Tomoaki Sato.
* predefined variable "tps"
The value of variable tps is taken from the scaling factor
specified by -s option.
* -D option
Variable values can be defined by -D option.
* \set command now allows arithmetic calculations.
2005/09/29
* add -f option. contributed by Tomoaki Sato.
[updation records were missing]
2003/11/26
* create indexes after data insertion to reduce time.
patch from Yutaka Tanida.
2003/06/10
* fix uninitialized memory bug
* add support for PGHOST, PGPORT, PGUSER environment variables
2002/07/20
* patch contributed by Neil Conway.
* code/document clean up and add -l option.
2002/02/24
* do not CHECKPOINT anymore while initializing benchmark
* database. Add -N option.
2001/10/24
* "time"->"mtime"
2001/09/09
* Add -U, -P, -C options
o History before contributed to PostgreSQL
2000/1/15 pgbench-1.2 contributed to PostgreSQL
* Add -v option

View File

@ -1,4 +1,6 @@
pgbench README 2006/10/21 Tatsuo Ishii
$PostgreSQL: pgsql/contrib/pgbench/README.pgbench_jis,v 1.17 2007/04/06 08:49:44 ishii Exp $
pgbench README
$B"#(Bpgbench $B$H$O!)(B
@ -283,57 +285,7 @@ pgbench $B$O@P0f(B $BC#IW$K$h$C$F=q$+$l$^$7$?!%%i%$%;%s%9>r7o$O(B pgbench.c
$BKAF,$K=q$$$F$"$j$^$9!%$3$N>r7o$r<i$k8B$jL5=~$GMxMQ$7!$$^$?<+M3$K:FG[IU(B
$B$G$-$^$9!%(B
$B"#2~DjMzNr(B
2006/10/21
* $B99$K%G%U%)%k%H$N%9%1!<%j%s%0%U%!%/%?$r(Bbranches$B$+$i<h$C$F$3$J(B
$B$$%P%0$r=$@5!%(B
2006/09/13
* $BJQ?t(Btps$B$OJ6$i$o$7$$$N$G(Bscale$B$KJQ99!%%G%U%)%k%H%7%J%j%*$N;~$K!$(B
$B%G%U%)%k%H$N%9%1!<%j%s%0%U%!%/%?$r(Bbranches$B$+$i<h$C$F$3$J$$%P%0$r=$@5!%(B
2006/07/26
* $B:4F#$5$s$N%Q%C%A$rE,MQ!%0J2<$N5!G=DI2C!%(BPostgreSQL 8.2$B$K<h$j(B
$B9~$^$l$^$9!%(B
$BJQ?t(B tps
-s $B%*%W%7%g%s$G;XDj$7$?%9%1!<%j%s%0%U%!%/%?!<$r%U%!%$%kFb$GJQ?t$H$7(B
$B$F;2>H$9$k5!G=(B
-D $B%*%W%7%g%s(B
$B%3%^%s%I$N%*%W%7%g%s$H$7$FDj5A$7$?JQ?t$r%U%!%$%kFb$+$i;2>H$9$k5!G=(B
\set $B%3%^%s%I(B
$B%U%!%$%kFb$G;MB'1i;;$r9T$$!"$=$N7k2L$rJQ?t$KBeF~$9$k5!G=(B
2005/09/29
* $B:4F#$5$s$N%Q%C%A$rE,MQ!%(B-f $B%*%W%7%g%s$NDI2C!%(B
[$B$3$N4V$$$m$$$mJQ99$,$"$C$?$h$&$@$,(BREADME$B$O%a%$%s%F%J%s%9$5$l$F$$$J$$(B]
2003/11/26
* $BC+ED$5$s$N%Q%C%A$rE,MQ!%(Bpgbench -i$B$N:]$K!$8e$+$i<g%-!<$r:n@.(B
$B$9$k$h$&$K$7$?!%$3$l$K$h$C$F=i4|2=$N<B9T;~4V$,BgI}$KC;=L$G$-(B
$B$k(B($B$O$:(B)$B!%(B
2003/06/10
* $B%a%b%j$,=i4|2=$5$l$F$$$J$$%P%0$r=$@5(B
* $B4D6-JQ?t(BPGHOST, PGPORT, PGUSER$B$rG'<1$9$k$h$&$K$7$?!%(B
2002/07/20
* Nei Conway$B$5$s$N%Q%C%A$rE,MQ!%(B
* -l $B%*%W%7%g%s$NDI2C!%(B
2002/02/24
* $B$3$3$+$i$O(B7.3$BMQ$NJQ99$G$9!%(B
* CHECKPOINT$B$NH/9T$r$d$a$^$7$?!%(B
* -N $B%*%W%7%g%s$rDI2C$7$^$7$?!%(B
2001/10/24
* PostgreSQL 7.2$B$G!$(B"time"$B$,M=Ls8l$K$J$C$?$N$G!$(B"mtime"$B$KJQ99(B
$B$7$?!%(B
2001/09/09
* PostgreSQL 7.2$BMQ$K!$(B-U, -P, -C $B%*%W%7%g%s$rDI2C$7$^$7$?!%(B
$B"#(BPostgreSQL$B$N(Bcontrib$B%b%8%e!<%k$H$7$F<h$j9~$^$l$k$^$G$N2~DjMzNr(B
2000/1/15 pgbench-1.2 $B$O(B PostgreSQL $B$K(B contribute $B$5$l$^$7$?!%(B
* -v $B%*%W%7%g%sDI2C(B

View File

@ -1,5 +1,5 @@
/*
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.62 2007/03/13 09:06:35 mha Exp $
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.63 2007/04/06 08:49:44 ishii Exp $
*
* pgbench: a simple benchmark program for PostgreSQL
* written by Tatsuo Ishii
@ -188,12 +188,26 @@ getrand(int min, int max)
return min + (int) (((max - min) * (double) random()) / MAX_RANDOM_VALUE + 0.5);
}
/* call PQexec() and exit() on failure */
static void
executeStatement(PGconn *con, const char* sql)
{
PGresult *res;
res = PQexec(con, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
}
/* set up a connection to the backend */
static PGconn *
doConnect(void)
{
PGconn *con;
PGresult *res;
con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
login, pwd);
@ -216,13 +230,7 @@ doConnect(void)
return (NULL);
}
res = PQexec(con, "SET search_path = public");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
executeStatement(con, "SET search_path = public");
return (con);
}
@ -720,18 +728,18 @@ init(void)
PGconn *con;
PGresult *res;
static char *DDLs[] = {
"drop table branches",
"drop table if exists branches",
"create table branches(bid int not null,bbalance int,filler char(88))",
"drop table tellers",
"drop table if exists tellers",
"create table tellers(tid int not null,bid int,tbalance int,filler char(84))",
"drop table accounts",
"drop table if exists accounts",
"create table accounts(aid int not null,bid int,abalance int,filler char(84))",
"drop table history",
"create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
"drop table if exists history",
"create table history(tid int,bid int,aid int,delta int,mtime timestamp,filler char(22))"};
static char *DDLAFTERs[] = {
"alter table branches add primary key (bid)",
"alter table tellers add primary key (tid)",
"alter table accounts add primary key (aid)"};
"alter table accounts add primary key (aid)"};
char sql[256];
@ -741,77 +749,46 @@ init(void)
if ((con = doConnect()) == NULL)
exit(1);
for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
{
res = PQexec(con, DDLs[i]);
if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
}
for (i = 0; i < lengthof(DDLs); i++)
executeStatement(con, DDLs[i]);
res = PQexec(con, "begin");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
executeStatement(con, "begin");
for (i = 0; i < nbranches * scale; i++)
{
snprintf(sql, 256, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
res = PQexec(con, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
executeStatement(con, sql);
}
for (i = 0; i < ntellers * scale; i++)
{
snprintf(sql, 256, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
,i + 1, i / ntellers + 1);
res = PQexec(con, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
executeStatement(con, sql);
}
res = PQexec(con, "end");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
executeStatement(con, "commit");
/*
* fill the accounts table with some data
*/
fprintf(stderr, "creating tables...\n");
executeStatement(con, "begin");
executeStatement(con, "truncate accounts");
res = PQexec(con, "copy accounts from stdin");
if (PQresultStatus(res) != PGRES_COPY_IN)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
/*
* occupy accounts table with some data
*/
fprintf(stderr, "creating tables...\n");
for (i = 0; i < naccounts * scale; i++)
{
int j = i + 1;
if (j % 10000 == 1)
{
res = PQexec(con, "copy accounts from stdin");
if (PQresultStatus(res) != PGRES_COPY_IN)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
}
snprintf(sql, 256, "%d\t%d\t%d\t\n", j, i / naccounts + 1, 0);
if (PQputline(con, sql))
{
@ -820,62 +797,32 @@ init(void)
}
if (j % 10000 == 0)
{
/*
* every 10000 tuples, we commit the copy command. this should
* avoid generating too much WAL logs
*/
fprintf(stderr, "%d tuples done.\n", j);
if (PQputline(con, "\\.\n"))
{
fprintf(stderr, "very last PQputline failed\n");
exit(1);
}
if (PQendcopy(con))
{
fprintf(stderr, "PQendcopy failed\n");
exit(1);
}
#ifdef NOT_USED
/*
* do a checkpoint to purge the old WAL logs
*/
res = PQexec(con, "checkpoint");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
#endif /* NOT_USED */
}
}
fprintf(stderr, "set primary key...\n");
for (i = 0; i < (sizeof(DDLAFTERs) / sizeof(char *)); i++)
if (PQputline(con, "\\.\n"))
{
res = PQexec(con, DDLAFTERs[i]);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
fprintf(stderr, "very last PQputline failed\n");
exit(1);
}
if (PQendcopy(con))
{
fprintf(stderr, "PQendcopy failed\n");
exit(1);
}
executeStatement(con, "commit");
/*
* create indexes
*/
fprintf(stderr, "set primary key...\n");
for (i = 0; i < lengthof(DDLAFTERs); i++)
executeStatement(con, DDLAFTERs[i]);
/* vacuum */
fprintf(stderr, "vacuum...");
res = PQexec(con, "vacuum analyze");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
fprintf(stderr, "done.\n");
executeStatement(con, "vacuum analyze");
fprintf(stderr, "done.\n");
PQfinish(con);
}
@ -1155,7 +1102,7 @@ main(int argc, char **argv)
int c;
int is_init_mode = 0; /* initialize mode? */
int is_no_vacuum = 0; /* no vacuum at all before testing? */
int is_full_vacuum = 0; /* do full vacuum before testing? */
int do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
int debug = 0; /* debug flag */
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
* 2: skip update of branches and tellers */
@ -1219,7 +1166,7 @@ main(int argc, char **argv)
is_no_vacuum++;
break;
case 'v':
is_full_vacuum++;
do_vacuum_accounts++;
break;
case 'p':
pgport = optarg;
@ -1456,49 +1403,16 @@ main(int argc, char **argv)
if (!is_no_vacuum)
{
fprintf(stderr, "starting vacuum...");
res = PQexec(con, "vacuum branches");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
res = PQexec(con, "vacuum tellers");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
res = PQexec(con, "delete from history");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
res = PQexec(con, "vacuum history");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
executeStatement(con, "vacuum branches");
executeStatement(con, "vacuum tellers");
executeStatement(con, "delete from history");
executeStatement(con, "vacuum history");
fprintf(stderr, "end.\n");
if (is_full_vacuum)
if (do_vacuum_accounts)
{
fprintf(stderr, "starting full vacuum...");
res = PQexec(con, "vacuum analyze accounts");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
PQclear(res);
fprintf(stderr, "starting vacuum accounts...");
executeStatement(con, "vacuum analyze accounts");
fprintf(stderr, "end.\n");
}
}