pgbench — run a benchmark test on PostgreSQL
pgbench -i [option...] [dbname]
pgbench [option...] [dbname]
pgbench is a simple program for running benchmark tests on PostgreSQL. It runs the same sequence of SQL commands over and over, possibly in multiple concurrent database sessions, and then calculates the average transaction rate (transactions per second). By default, pgbench tests a scenario that is loosely based on TPC-B, involving five SELECT, UPDATE, and INSERT commands per transaction. However, it is easy to test other cases by writing your own transaction script files.
Typical output from pgbench looks like:
transaction type: <builtin: TPC-B (sort of)> scaling factor: 10 query mode: simple number of clients: 10 number of threads: 1 maximum number of tries: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 number of failed transactions: 0 (0.000%) latency average = 11.013 ms latency stddev = 7.351 ms initial connection time = 45.758 ms tps = 896.967014 (without initial connection time)
The first seven lines report some of the most important parameter settings. The sixth line reports the maximum number of tries for transactions with serialization or deadlock errors (see Failures and Serialization/Deadlock Retries for more information). The eighth line reports the number of transactions completed and intended (the latter being just the product of number of clients and number of transactions per client); these will be equal unless the run failed before completion or some SQL command(s) failed. (In -T mode, only the actual number of transactions is printed.) The next line reports the number of failed transactions (see Failures and Serialization/Deadlock Retries for more information). The last line reports the number of transactions per second.
The default TPC-B-like transaction test requires specific tables to be set up beforehand. pgbench should be invoked with the -i (initialize) option to create and populate these tables. (When you are testing a custom script, you don't need this step, but will instead need to do whatever setup your test needs.) Initialization looks like:
pgbench -i [other-options]dbname
where dbname is the name of the already-created database to test in. (You may also need -h, -p, and/or -U options to specify how to connect to the database server.)
pgbench -i creates four tables pgbench_accounts, pgbench_branches, pgbench_history, and pgbench_tellers, destroying any existing tables of these names. Be very careful to use another database if you have tables having these names!
At the default “scale factor” of 1, the tables initially contain this many rows:
table # of rows --------------------------------- pgbench_branches 1 pgbench_tellers 10 pgbench_accounts 100000 pgbench_history 0
You can (and, for most purposes, probably should) increase the number of rows by using the -s (scale factor) option. The -F (fillfactor) option might also be used at this point.
Once you have done the necessary setup, you can run your benchmark with a command that doesn't include -i, that is
pgbench [options]dbname
In nearly all cases, you'll need some options to make a useful test. The most important options are -c (number of clients), -t (number of transactions), -T (time limit), and -f (specify a custom script file). See below for a full list.
The following is divided into three subsections. Different options are used during database initialization and while running benchmarks, but some options are useful in both cases.
pgbench accepts the following command-line initialization arguments:
[-d] dbname[--dbname=]dbname #Specifies the name of the database to test in. If this is not specified, the environment variable PGDATABASE is used. If that is not set, the user name specified for the connection is used.
-i--initialize #Required to invoke initialization mode.
-I init_steps--init-steps=init_steps #Perform just a selected set of the normal initialization steps. init_steps specifies the initialization steps to be performed, using one character per step. Each step is invoked in the specified order. The default is dtgvp. The available steps are:
d (Drop) #Drop any existing pgbench tables.
t (create Tables) #Create the tables used by the standard pgbench scenario, namely pgbench_accounts, pgbench_branches, pgbench_history, and pgbench_tellers.
g or G (Generate data, client-side or server-side) #Generate data and load it into the standard tables, replacing any data already present.
With g (client-side data generation), data is generated in pgbench client and then sent to the server. This uses the client/server bandwidth extensively through a COPY. pgbench uses the FREEZE option to load data into ordinary (non-partition) tables with version 14 or later of PostgreSQL to speed up subsequent VACUUM. Using g causes logging to print one message every 100,000 rows while generating data for all tables.
With G (server-side data generation), only small queries are sent from the pgbench client and then data is actually generated in the server. No significant bandwidth is required for this variant, but the server will do more work. Using G causes logging not to print any progress message while generating data.
The default initialization behavior uses client-side data generation (equivalent to g).
v (Vacuum) #Invoke VACUUM on the standard tables.
p (create Primary keys) #Create primary key indexes on the standard tables.
f (create Foreign keys) #Create foreign key constraints between the standard tables. (Note that this step is not performed by default.)
-F fillfactor--fillfactor=fillfactor #Create the pgbench_accounts, pgbench_tellers and pgbench_branches tables with the given fillfactor. Default is 100.
-n--no-vacuum #Perform no vacuuming during initialization. (This option suppresses the v initialization step, even if it was specified in -I.)
-q--quiet #Switch logging to quiet mode, producing only one progress message per 5 seconds. The default logging prints one message each 100,000 rows, which often outputs many lines per second (especially on good hardware).
This setting has no effect if G is specified in -I.
-s scale_factor--scale=scale_factor #Multiply the number of rows generated by the scale factor. For example, -s 100 will create 10,000,000 rows in the pgbench_accounts table. Default is 1. When the scale is 20,000 or larger, the columns used to hold account identifiers (aid columns) will switch to using larger integers (bigint), in order to be big enough to hold the range of account identifiers.
--foreign-keys #Create foreign key constraints between the standard tables. (This option adds the f step to the initialization step sequence, if it is not already present.)
--index-tablespace=index_tablespace #Create indexes in the specified tablespace, rather than the default tablespace.
--partition-method=NAME #Create a partitioned pgbench_accounts table with NAME method. Expected values are range or hash. This option requires that --partitions is set to non-zero. If unspecified, default is range.
--partitions=NUM #Create a partitioned pgbench_accounts table with NUM partitions of nearly equal size for the scaled number of accounts. Default is 0, meaning no partitioning.
--tablespace=tablespace #Create tables in the specified tablespace, rather than the default tablespace.
--unlogged-tables #Create all tables as unlogged tables, rather than permanent tables.
pgbench accepts the following command-line benchmarking arguments:
-b scriptname[@weight]--builtin=scriptname[@weight] #Add the specified built-in script to the list of scripts to be executed. Available built-in scripts are: tpcb-like, simple-update and select-only. Unambiguous prefixes of built-in names are accepted. With the special name list, show the list of built-in scripts and exit immediately.
Optionally, write an integer weight after @ to adjust the probability of selecting this script versus other ones. The default weight is 1. See below for details.
-c clients--client=clients #Number of clients simulated, that is, number of concurrent database sessions. Default is 1.
-C--connect #Establish a new connection for each transaction, rather than doing it just once per client session. This is useful to measure the connection overhead.
-D varname=value--define=varname=value #Define a variable for use by a custom script (see below). Multiple -D options are allowed.
-f filename[@weight]--file=filename[@weight] #Add a transaction script read from filename to the list of scripts to be executed.
Optionally, write an integer weight after @ to adjust the probability of selecting this script versus other ones. The default weight is 1. (To use a script file name that includes an @ character, append a weight so that there is no ambiguity, for example filen@me@1.) See below for details.
-j threads--jobs=threads #Number of worker threads within pgbench. Using more than one thread can be helpful on multi-CPU machines. Clients are distributed as evenly as possible among available threads. Default is 1.
-l--log #Write information about each transaction to a log file. See below for details.
-L limit--latency-limit=limit #Transactions that last more than limit milliseconds are counted and reported separately, as late.
When throttling is used (--rate=...), transactions that lag behind schedule by more than limit ms, and thus have no hope of meeting the latency limit, are not sent to the server at all. They are counted and reported separately as skipped.
When the --max-tries option is used, a transaction which fails due to a serialization anomaly or from a deadlock will not be retried if the total time of all its tries is greater than limit ms. To limit only the time of tries and not their number, use --max-tries=0. By default, the option --max-tries is set to 1 and transactions with serialization/deadlock errors are not retried. See Failures and Serialization/Deadlock Retries for more information about retrying such transactions.
-M querymode--protocol=querymode #Protocol to use for submitting queries to the server:
simple: use simple query protocol.
extended: use extended query protocol.
prepared: use extended query protocol with prepared statements.
In the prepared mode, pgbench reuses the parse analysis result starting from the second query iteration, so pgbench runs faster than in other modes.
The default is simple query protocol. (See Chapter 54 for more information.)
-n--no-vacuum #Perform no vacuuming before running the test. This option is necessary if you are running a custom test scenario that does not include the standard tables pgbench_accounts, pgbench_branches, pgbench_history, and pgbench_tellers.
-N--skip-some-updates #Run built-in simple-update script. Shorthand for -b simple-update.
-P sec--progress=sec #Show progress report every sec seconds. The report includes the time since the beginning of the run, the TPS since the last report, and the transaction latency average, standard deviation, and the number of failed transactions since the last report. Under throttling (-R), the latency is computed with respect to the transaction scheduled start time, not the actual transaction beginning time, thus it also includes the average schedule lag time. When --max-tries is used to enable transaction retries after serialization/deadlock errors, the report includes the number of retried transactions and the sum of all retries.
-r--report-per-command #Report the following statistics for each command after the benchmark finishes: the average per-statement latency (execution time from the perspective of the client), the number of failures, and the number of retries after serialization or deadlock errors in this command. The report displays retry statistics only if the --max-tries option is not equal to 1.
-R rate--rate=rate #Execute transactions targeting the specified rate instead of running as fast as possible (the default). The rate is given in transactions per second. If the targeted rate is above the maximum possible rate, the rate limit won't impact the results.
The rate is targeted by starting transactions along a Poisson-distributed schedule time line. The expected start time schedule moves forward based on when the client first started, not when the previous transaction ended. That approach means that when transactions go past their original scheduled end time, it is possible for later ones to catch up again.
When throttling is active, the transaction latency reported at the end of the run is calculated from the scheduled start times, so it includes the time each transaction had to wait for the previous transaction to finish. The wait time is called the schedule lag time, and its average and maximum are also reported separately. The transaction latency with respect to the actual transaction start time, i.e., the time spent executing the transaction in the database, can be computed by subtracting the schedule lag time from the reported latency.
If --latency-limit is used together with --rate, a transaction can lag behind so much that it is already over the latency limit when the previous transaction ends, because the latency is calculated from the scheduled start time. Such transactions are not sent to the server, but are skipped altogether and counted separately.
A high schedule lag time is an indication that the system cannot process transactions at the specified rate, with the chosen number of clients and threads. When the average transaction execution time is longer than the scheduled interval between each transaction, each successive transaction will fall further behind, and the schedule lag time will keep increasing the longer the test run is. When that happens, you will have to reduce the specified transaction rate.
-s scale_factor--scale=scale_factor #Report the specified scale factor in pgbench's output. With the built-in tests, this is not necessary; the correct scale factor will be detected by counting the number of rows in the pgbench_branches table. However, when testing only custom benchmarks (-f option), the scale factor will be reported as 1 unless this option is used.
-S--select-only #Run built-in select-only script. Shorthand for -b select-only.
-t transactions--transactions=transactions #Number of transactions each client runs. Default is 10.
-T seconds--time=seconds #Run the test for this many seconds, rather than a fixed number of transactions per client. -t and -T are mutually exclusive.
-v--vacuum-all #Vacuum all four standard tables before running the test. With neither -n nor -v, pgbench will vacuum the pgbench_tellers and pgbench_branches tables, and will truncate pgbench_history.
--aggregate-interval=seconds #Length of aggregation interval (in seconds). May be used only with -l option. With this option, the log contains per-interval summary data, as described below.
--continue-on-error #Allows clients to continue running even if an SQL statement fails due to errors other than serialization or deadlock. By default, clients abort after such errors, but with this option enabled, they proceed to the next transaction instead. Note that clients still abort even with this option if an error causes the connection to fail. See Failures and Serialization/Deadlock Retries for more information.
This option is useful when your custom script may raise errors such as unique constraint violations, but you want the benchmark to continue and measure performance including those failures.
--exit-on-abort #Exit immediately when any client is aborted due to some error. Without this option, even when a client is aborted, other clients could continue their run as specified by -t or -T option, and pgbench will print an incomplete results in this case.
Note that serialization failures or deadlock failures do not abort the client, so they are not affected by this option. See Failures and Serialization/Deadlock Retries for more information.
--failures-detailed #Report failures in per-transaction and aggregation logs, as well as in the main and per-script reports, grouped by the following types:
serialization failures;
deadlock failures;
other failures;
See Failures and Serialization/Deadlock Retries for more information.
--log-prefix=prefix #Set the filename prefix for the log files created by --log. The default is pgbench_log.
--max-tries=number_of_tries #Enable retries for transactions with serialization/deadlock errors and set the maximum number of these tries. This option can be combined with the --latency-limit option which limits the total time of all transaction tries; moreover, you cannot use an unlimited number of tries (--max-tries=0) without --latency-limit or --time. The default value is 1 and transactions with serialization/deadlock errors are not retried. See Failures and Serialization/Deadlock Retries for more information about retrying such transactions.
--progress-timestamp #When showing progress (option -P), use a timestamp (Unix epoch) instead of the number of seconds since the beginning of the run. The unit is in seconds, with millisecond precision after the dot. This helps compare logs generated by various tools.
--random-seed=seed #Set random generator seed. Seeds the system random number generator, which then produces a sequence of initial generator states, one for each thread. Values for seed may be: time (the default, the seed is based on the current time), rand (use a strong random source, failing if none is available), or an unsigned decimal integer value. The random generator is invoked explicitly from a pgbench script (random... functions) or implicitly (for instance option --rate uses it to schedule transactions). When explicitly set, the value used for seeding is shown on the terminal. Any value allowed for seed may also be provided through the environment variable PGBENCH_RANDOM_SEED. To ensure that the provided seed impacts all possible uses, put this option first or use the environment variable.
Setting the seed explicitly allows to reproduce a pgbench run exactly, as far as random numbers are concerned. As the random state is managed per thread, this means the exact same pgbench run for an identical invocation if there is one client per thread and there are no external or data dependencies. From a statistical viewpoint reproducing runs exactly is a bad idea because it can hide the performance variability or improve performance unduly, e.g., by hitting the same pages as a previous run. However, it may also be of great help for debugging, for instance re-running a tricky case which leads to an error. Use wisely.
--sampling-rate=rate #Sampling rate, used when writing data into the log, to reduce the amount of log generated. If this option is given, only the specified fraction of transactions are logged. 1.0 means all transactions will be logged, 0.05 means only 5% of the transactions will be logged.
Remember to take the sampling rate into account when processing the log file. For example, when computing TPS values, you need to multiply the numbers accordingly (e.g., with 0.01 sample rate, you'll only get 1/100 of the actual TPS).
--show-script=scriptname #Show the actual code of builtin script scriptname on stderr, and exit immediately.
--verbose-errors #Print messages about all errors and failures (errors without retrying) including which limit for retries was exceeded and how far it was exceeded for the serialization/deadlock failures. (Note that in this case the output can be significantly increased.) See Failures and Serialization/Deadlock Retries for more information.
pgbench also accepts the following common command-line arguments for connection parameters and other common settings: