If you use "pgbench -S -M prepared" at a scale where all data fits in
memory, most of what you are benchmarking is network/IPC chatter, and
table locking.  Which is fine if that is what you want to do.  This
patch adds a new transaction type of -P, which does the same thing as
-S but it moves the main loop of selects, 10,000 at at time, into
pl/pgSQL.  This does a good job of exercising the executor rather than
IPC.

This can simulate workloads that have primary key look ups as the
inner side of large nested loop.  It is also useful for isolating and
profiling parts of the backend code.

I did not implement this as a new query mode (-M plpgsql), because the
lack of transaction control in pl/pgSQL means it can only be used for
select-only transactions rather than as a general method.  So I
thought a new transaction type made more sense.

I didn't implement it as a custom file using -f because:
1) It seems to be a natural extension of the existing built-ins.  Also
-f is fiddly.  Several times I've wanted to ask posters who are
discussing the other built in transactions to run something like this
and report back, which is easier to do if it is also builtin.
2) It uses a initialization code which -f does not support.
3) I don't see how I can make it automatically detect and respond to
:scale if it were run under -f.

Perhaps issues 2 and 3 would be best addressed by extending the
general -f facility, but that would be a lot more work, and I don't
know how well received it would be.

The reporting might be an issue.  I don't want to call it TPS when it
is really not a transaction being reported, so for now I've just left
the TPS as as true transactions, and added a separate reporting line
for selects per second.

I know I also need to add to the web-docs, but I'm hoping to wait on
that until I get some feedback on whether the whole approach is
considered to be viable or not.

some numbers for single client runs on 64-bit AMD Opteron Linux:

12,567 sps  under -S
19,646 sps  under -S -M prepared
58,165 sps  under -P

Cheers,

Jeff
diff --git a/contrib/pgbench/pgbench.c b/contrib/pgbench/pgbench.c
index bb18c89..9a43fd5 100644
*** a/contrib/pgbench/pgbench.c
--- b/contrib/pgbench/pgbench.c
*************** int			fillfactor = 100;
*** 130,135 ****
--- 130,136 ----
  								 * -s instead */
  #define ntellers	10
  #define naccounts	100000
+ #define plpgsql_loops	10000
  
  bool		use_log;			/* log transaction latencies to a file */
  bool		is_connect;			/* establish connection for each transaction */
*************** static char *select_only = {
*** 273,278 ****
--- 274,284 ----
  	"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
  };
  
+ /* -P case */
+ static char *select_only_plpgsql = {
+ 	"SELECT pgbench_query(" CppAsString2(naccounts) " *:scale," CppAsString2(plpgsql_loops) ");\n"
+ };
+ 
  /* Function prototypes */
  static void setalarm(int seconds);
  static void *threadRun(void *arg);
*************** printResults(int ttype, int normal_xacts
*** 1686,1691 ****
--- 1692,1699 ----
  		s = "Update only pgbench_accounts";
  	else if (ttype == 1)
  		s = "SELECT only";
+ 	else if (ttype == 4)
+ 		s = "SELECT only via plpgsql";
  	else
  		s = "Custom query";
  
*************** printResults(int ttype, int normal_xacts
*** 1708,1713 ****
--- 1716,1726 ----
  	}
  	printf("tps = %f (including connections establishing)\n", tps_include);
  	printf("tps = %f (excluding connections establishing)\n", tps_exclude);
+     if (ttype==4)
+ 	{
+ 		printf("selects per second = %f (including connections establishing)\n", tps_include*plpgsql_loops);
+ 		printf("selects per second = %f (excluding connections establishing)\n", tps_exclude*plpgsql_loops);
+ 	};
  
  	/* Report per-command latencies */
  	if (is_latencies)
*************** main(int argc, char **argv)
*** 1766,1772 ****
  	int			is_no_vacuum = 0;		/* no vacuum at all before testing? */
  	int			do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
  	int			ttype = 0;		/* transaction type. 0: TPC-B, 1: SELECT only,
! 								 * 2: skip update of branches and tellers */
  	char	   *filename = NULL;
  	bool		scale_given = false;
  
--- 1779,1785 ----
  	int			is_no_vacuum = 0;		/* no vacuum at all before testing? */
  	int			do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
  	int			ttype = 0;		/* transaction type. 0: TPC-B, 1: SELECT only,
! 								 * 2: skip update of branches and tellers 3: custom sql, 4: SELECT only via plpgsql*/
  	char	   *filename = NULL;
  	bool		scale_given = false;
  
*************** main(int argc, char **argv)
*** 1823,1829 ****
  	state = (CState *) xmalloc(sizeof(CState));
  	memset(state, 0, sizeof(CState));
  
! 	while ((c = getopt(argc, argv, "ih:nvp:dSNc:j:Crs:t:T:U:lf:D:F:M:")) != -1)
  	{
  		switch (c)
  		{
--- 1836,1842 ----
  	state = (CState *) xmalloc(sizeof(CState));
  	memset(state, 0, sizeof(CState));
  
! 	while ((c = getopt(argc, argv, "ih:nvp:dSNPc:j:Crs:t:T:U:lf:D:F:M:")) != -1)
  	{
  		switch (c)
  		{
*************** main(int argc, char **argv)
*** 1851,1856 ****
--- 1864,1872 ----
  			case 'N':
  				ttype = 2;
  				break;
+ 			case 'P':
+ 				ttype = 4;
+ 				break;
  			case 'c':
  				nclients = atoi(optarg);
  				if (nclients <= 0 || nclients > MAXCLIENTS)
*************** main(int argc, char **argv)
*** 2100,2105 ****
--- 2116,2138 ----
  					scale);
  	}
  
+ 	if (ttype == 4)
+ 	{
+ 		executeStatement(con,
+ 			"create or replace function pgbench_query(scale integer,loops integer) RETURNS integer AS $$ "
+ 			"DECLARE sum integer default 0; "
+ 			"amount integer; "
+ 			"account_id integer; "
+ 			"BEGIN FOR i IN 1..loops LOOP "
+ 			"   account_id=1+floor(random()*scale); "
+ 			"   SELECT abalance into strict amount FROM pgbench_accounts WHERE aid = account_id; "
+ 			"   sum := sum + amount; "
+ 			"END LOOP; "
+ 			"return sum; "
+ 			"END $$ LANGUAGE plpgsql ");
+ 		fprintf(stderr, "plgsql function created.\n");
+ 	};
+ 
  	/*
  	 * :scale variables normally get -s or database scale, but don't override
  	 * an explicit -D switch
*************** main(int argc, char **argv)
*** 2153,2158 ****
--- 2186,2196 ----
  			num_files = 1;
  			break;
  
+ 		case 4:
+ 			sql_files[0] = process_builtin(select_only_plpgsql);
+ 			num_files = 1;
+ 			break;
+ 
  		default:
  			break;
  	}
-- 
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