From 7e96269a82d0f92db6066b1e30df5931ac1ad130 Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii <ishii@postgresql.org>
Date: Fri, 6 Apr 2007 08:49:44 +0000
Subject: [PATCH] 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!
--------------------------------------------------------------------------
---
 contrib/pgbench/README.pgbench     |  53 +------
 contrib/pgbench/README.pgbench_jis |  56 +-------
 contrib/pgbench/pgbench.c          | 220 +++++++++--------------------
 3 files changed, 75 insertions(+), 254 deletions(-)

diff --git a/contrib/pgbench/README.pgbench b/contrib/pgbench/README.pgbench
index d576b594a9f..7fc683cef03 100644
--- a/contrib/pgbench/README.pgbench
+++ b/contrib/pgbench/README.pgbench
@@ -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
diff --git a/contrib/pgbench/README.pgbench_jis b/contrib/pgbench/README.pgbench_jis
index adb22af4051..5afa9324367 100644
--- a/contrib/pgbench/README.pgbench_jis
+++ b/contrib/pgbench/README.pgbench_jis
@@ -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
 
 ■pgbench とは?
 
@@ -283,57 +285,7 @@ pgbench は石井 達夫によって書かれました.ライセンス条件は pgbench.c
 冒頭に書いてあります.この条件を守る限り無償で利用し,また自由に再配付
 できます.
 
-■改定履歴
-
-2006/10/21
-	* 更にデフォルトのスケーリングファクタをbranchesから取ってこな
-          いバグを修正.
-
-2006/09/13
-	* 変数tpsは紛らわしいのでscaleに変更.デフォルトシナリオの時に,
-	  デフォルトのスケーリングファクタをbranchesから取ってこないバグを修正.
-
-2006/07/26
-	* 佐藤さんのパッチを適用.以下の機能追加.PostgreSQL 8.2に取り
-	込まれます.
-
-	変数 tps
-	    -s オプションで指定したスケーリングファクターをファイル内で変数とし
-	   て参照する機能
-        -D オプション
-	   コマンドのオプションとして定義した変数をファイル内から参照する機能
-	\set コマンド
-	   ファイル内で四則演算を行い、その結果を変数に代入する機能
-
-2005/09/29
-	* 佐藤さんのパッチを適用.-f オプションの追加.
-
-[この間いろいろ変更があったようだがREADMEはメインテナンスされていない]
-
-2003/11/26
-	* 谷田さんのパッチを適用.pgbench -iの際に,後から主キーを作成
-	  するようにした.これによって初期化の実行時間が大幅に短縮でき
-	  る(はず).
-
-2003/06/10
-	* メモリが初期化されていないバグを修正
-	* 環境変数PGHOST, PGPORT, PGUSERを認識するようにした.
-
-2002/07/20
-	* Nei Conwayさんのパッチを適用.
-	* -l オプションの追加.
-
-2002/02/24
-	* ここからは7.3用の変更です.
-	* CHECKPOINTの発行をやめました.
-	* -N オプションを追加しました.
-
-2001/10/24
-	* PostgreSQL 7.2で,"time"が予約語になったので,"mtime"に変更
-	した.
-
-2001/09/09
-	* PostgreSQL 7.2用に,-U, -P, -C オプションを追加しました.
+■PostgreSQLのcontribモジュールとして取り込まれるまでの改定履歴
 
 2000/1/15 pgbench-1.2 は PostgreSQL に contribute されました.
 	* -v オプション追加
diff --git a/contrib/pgbench/pgbench.c b/contrib/pgbench/pgbench.c
index 1f2e0bf4167..369b7669f12 100644
--- a/contrib/pgbench/pgbench.c
+++ b/contrib/pgbench/pgbench.c
@@ -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);
 	}
-
-	/* vacuum */
-	fprintf(stderr, "vacuum...");
-	res = PQexec(con, "vacuum analyze");
-	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	if (PQendcopy(con))
 	{
-		fprintf(stderr, "%s", PQerrorMessage(con));
+		fprintf(stderr, "PQendcopy failed\n");
 		exit(1);
 	}
-	PQclear(res);
-	fprintf(stderr, "done.\n");
+	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...");
+	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");
 		}
 	}
-- 
GitLab