pgbench
pgbench — 运行 PostgreSQL 基准测试
当前查看 PostgreSQL 18.6。
说明
pgbench — 运行 PostgreSQL 基准测试
- 手册中的可执行程序
- “ 事务 ”
- 程序版本
- 18.6
- 参考清单
- 客户端程序
- 选项定义组
- 47
用法
pgbench -i [ option ...] [ dbname ]
pgbench [ option ...] [ dbname ]手册中的选项
| 选项与参数 | 说明 |
|---|---|
| -i --initialize | 进入初始化模式所必需。 |
| -I init_steps --init-steps= init_steps | 仅执行正常初始化步骤中的选定部分。 init_steps 指定要执行的初始化步骤,每个步骤用一个字符表示。各步骤会按照指定顺序调用。默认值为 dtgvp 。可用步骤如下: |
| -F fillfactor --fillfactor= fillfactor | 使用给定的 fillfactor 创建 pgbench_accounts、pgbench_tellers 和 pgbench_branches 表。默认值为 100。 |
| -n --no-vacuum | 初始化期间不执行清理。(此选项会抑制 v 初始化步骤,即使 -I 中已指定该步骤。) |
| -q --quiet | 将日志切换为静默模式,每 5 秒只输出一条进度消息。默认日志每生成 100,000 行输出一条消息,因而往往会在每秒输出多行(尤其是在较好的硬件上)。 |
| -s scale_factor --scale= scale_factor | 将生成的行数乘以规模因子。例如,-s 100 会在 pgbench_accounts 表中创建 10,000,000 行。默认值为 1。当规模因子达到 20,000 或更大时,存放账户标识符的列(aid 列)会改用更大的整数类型(bigint),以容纳所需的账户标识符范围。 |
| --foreign-keys | 在标准表之间创建外键约束。(如果初始化步骤序列中尚未包含 f 步骤,则此选项会把它加入进去。) |
| --index-tablespace= index_tablespace | 在指定的表空间中创建索引,而不是默认的表空间。 |
| --partition-method= NAME | 使用 NAME 方法创建分区的 pgbench_accounts 表。可选值为 range 或 hash。此选项要求 --partitions 为非零值。未指定时默认为 range。 |
| --partitions= NUM | 为按规模因子确定的账户数量创建具有 NUM 个分区的 pgbench_accounts 表,各分区大小大致相等。默认值为 0,表示不分区。 |
| --tablespace= tablespace | 在指定的表空间中创建表,而不是默认的表空间。 |
| --unlogged-tables | 将所有表创建为不记录 WAL 的表,而不是永久表。 |
| -b scriptname[@weight] --builtin = scriptname[@weight] | 将指定的内置脚本添加到待执行脚本列表中。可用的内置脚本包括: tpcb-like 、 simple-update 和 select-only 。也接受内置名称的无歧义前缀。使用特殊名称 list 时,会显示内置脚本列表并立即退出。 |
| -c clients --client= clients | 模拟的客户端数量,即并发数据库会话数。默认值为 1。 |
| -C --connect | 为每个事务建立一个新连接,而不是仅在每个客户端会话中执行一次。这对于测量连接开销很有用。 |
| -D varname = value --define= varname = value | 定义一个变量,供自定义脚本使用(见下文)。允许使用多个 -D 选项。 |
| -f filename[@weight] --file= filename[@weight] | 将从 filename 读取的事务脚本添加到要执行的脚本列表中。 |
| -j threads --jobs= threads | pgbench 内部的工作线程数。在多 CPU 机器上,使用多个线程可能有帮助。客户端会尽可能均匀地分配到可用线程中。默认值为 1。 |
| -l --log | 将每个事务的信息写入日志文件。详情见下文。 |
| -L limit --latency-limit= limit | 持续时间超过 limit 毫秒的事务会被单独计数和报告,称为 late 。 |
| -M querymode --protocol= querymode | 用于向服务器提交查询的协议: |
| -n --no-vacuum | 在运行测试前不执行任何清理。如果运行的是不包含标准表 pgbench_accounts 、 pgbench_branches 、 pgbench_history 和 pgbench_tellers 的自定义测试场景,则此选项是 必需的 。 |
| -N --skip-some-updates | 运行内置的 simple-update 脚本。是 -b simple-update 的简写。 |
| -P sec --progress= sec | 每 sec 秒显示一次进度报告。报告包括自运行开始以来的时间、自上次报告以来的 TPS、自上次报告以来事务延迟的平均值和标准差,以及失败事务数。使用限流( -R )时,延迟是相对于事务计划开始时间计算的,而不是实际开始时间,因此其中也包含平均计划滞后时间。当使用 --max-tries 启用事务在串行化/死锁错误后的重试时,报告还会包含发生过重试的事务数以及总重试次数。 |
| -r --report-per-command | 基准测试结束后,为每条命令报告以下统计信息:每条语句的平均延迟(从客户端角度衡量的执行时间)、失败次数,以及该命令发生序列化错误或死锁后的重试次数。只有 --max-tries 选项不等于 1 时,报告才会显示重试统计。 |
| -R rate --rate= rate | 以指定速率执行事务,而不是像默认行为那样尽可能快地运行。速率以每秒事务数表示。如果目标速率高于可达到的最大速率,则速率限制不会影响结果。 |
| -s scale_factor --scale= scale_factor | 在 pgbench 输出中报告指定的比例因子。对于内置测试,这没有必要;系统会通过统计 pgbench_branches 表中的行数来检测正确的比例因子。但在只测试自定义基准( -f 选项)时,除非使用此选项,否则比例因子会被报告为 1。 |
| -S --select-only | 运行内置的 select-only 脚本。是 -b select-only 的简写。 |
| -t transactions --transactions= transactions | 每个客户端运行的事务数量。默认值为10。 |
| -T seconds --time= seconds | 让测试运行指定的秒数,而不是让每个客户端执行固定数量的事务。 -t 和 -T 是互斥的。 |
| -v --vacuum-all | 在运行测试之前,对四个标准表全部执行清理。如果既不使用 -n 也不使用 -v , pgbench 会对 pgbench_tellers 和 pgbench_branches 表进行清理,并截断 pgbench_history 。 |
| --aggregate-interval= seconds | 聚合间隔的长度(以秒为单位)。只能与 -l 选项一起使用。使用此选项时,日志包含每个间隔的摘要数据,如下所述。 |
| --exit-on-abort | 当任一客户端因错误被中止时,立即退出。如果不指定该选项,即使某个客户端被中止,其他客户端仍可按 -t 或 -T 的设定继续运行,此时 pgbench 会输出不完整的结果。 |
| --failures-detailed | 在逐事务日志、聚合日志以及主报告和逐脚本报告中,按以下类型分组报告失败: |
| --log-prefix= prefix | 设置由 --log 创建的日志文件的文件名前缀。默认值为 pgbench_log 。 |
| --max-tries= number_of_tries | 为发生序列化错误或死锁的事务启用重试,并设置最大尝试次数。此选项可以与 --latency-limit 一起使用,后者限制同一事务所有尝试的总耗时;此外,只有指定 --latency-limit 或 --time,才允许使用无限尝试次数(--max-tries=0)。默认值为 1,发生序列化错误或死锁的事务不会重试。有关此类事务重试的更多信息,参见“失败与序列化/死锁重试”。 |
| --progress-timestamp | 显示进度(选项 -P )时,使用时间戳(Unix 纪元)而不是自运行开始以来的秒数。单位为秒,小数点后精确到毫秒。这有助于比较各种工具生成的日志。 |
| --random-seed= seed | 设置随机数生成器种子。它会先为系统随机数生成器设种,再生成一系列初始生成器状态,每个线程一个。 seed 的取值可以是: time (默认值,种子基于当前时间), rand (使用强随机源,如果没有可用的则失败),或者无符号十进制整数值。随机生成器既可以在 pgbench 脚本中显式调用( random... 函数),也可以隐式调用(例如选项 --rate 用于调度事务)。显式设置时,实际用于设种的值会显示在终端上。任何允许的 seed 值也可以通过环境变量 PGBENCH_RANDOM_SEED 提供。为确保提供的种子影响所有可能的用途,将此选项放在第一位或使用环境变量。 |
| --sampling-rate= rate | 写入日志时使用的采样率,用于减少生成的日志量。如果给定此选项,则只记录指定比例的事务。1.0 表示记录全部事务,0.05 表示只记录 5% 的事务。 |
| --show-script= scriptname | 将内置脚本 scriptname 的实际代码输出到 stderr,然后立即退出。 |
| --verbose-errors | 打印关于所有错误和失败(不再重试的错误)的消息,包括超出了哪一种重试限制,以及对于串行化/死锁失败超出的幅度。(请注意,这种情况下输出量可能会显著增加。)更多信息见 失败和串行化/死锁重试 。 |
| --debug | 打印调试输出。 |
| -h hostname --host= hostname | 数据库服务器的主机名。 |
| -p port --port= port | 数据库服务器的端口号。 |
| -U login --username= login | 连接时使用的用户名。 |
| -V --version | 打印 pgbench 版本并退出。 |
| -? --help | 显示 pgbench 命令行参数的帮助信息并退出。 |
环境变量
| 变量 | 含义 |
|---|---|
| PGDATABASE PGHOST PGPORT PGUSER | 默认连接参数。 |
手册定义
“事务”
pgbench — 运行 PostgreSQL 基准测试
大纲
pgbench -i [option...] [dbname]
pgbench [option...] [dbname]
说明
pgbench是一个用于对PostgreSQL执行基准测试的简单程序。它会反复执行同一组 SQL 命令,也可在多个并发数据库会话中运行,然后计算平均事务速率(每秒事务数)。默认情况下,pgbench测试的是一个大体上基于 TPC-B 的场景,每个事务包含五条SELECT、UPDATE和INSERT命令。不过,通过编写自己的事务脚本文件,也很容易测试其他场景。
典型的pgbench输出如下:
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)
前七行给出了若干最重要的参数设置。第六行报告了出现串行化或死锁错误时事务允许的最大尝试次数(更多信息见失败和串行化/死锁重试)。第八行报告实际完成的事务数和预期事务数(后者仅为客户端数量与每个客户端事务数的乘积);除非运行在完成前失败,或者某些 SQL 命令执行失败,否则两者应当相等。(在-T模式下,只打印实际事务数。)下一行报告因串行化或死锁错误而失败的事务数(更多信息见失败和串行化/死锁重试)。最后一行报告每秒事务数。
默认的类 TPC-B 事务测试要求预先建立特定的表。应使用-i(初始化)选项调用pgbench来创建并填充这些表。(测试自定义脚本时不需要这一步,但需要自行完成测试所需的准备工作。)初始化命令如下:
pgbench -i [other-options]dbname
其中dbname是已创建好的、用于执行测试的数据库名称。(可能还需要使用-h、-p和/或-U选项来指定如何连接到数据库服务器。)
小心
pgbench -i会创建四个表pgbench_accounts、pgbench_branches、pgbench_history和pgbench_tellers,并销毁任何已存在的同名表。如果数据库中已经存在这些名称的表,请务必改用其他数据库!
在默认的“比例因子” 1 下,这些表最初包含如下行数:
table # of rows --------------------------------- pgbench_branches 1 pgbench_tellers 10 pgbench_accounts 100000 pgbench_history 0
可以使用-s(比例因子)选项来增加行数,而且在大多数场景下通常也应该这样做。此时还可以配合使用-F(fillfactor)选项。
完成必要的准备后,就可以使用不带-i的命令运行基准测试,也就是:
pgbench [options]dbname
几乎在所有情况下,都需要附加一些选项才能得到有意义的测试。最重要的选项是-c(客户端数)、-t(事务数)、-T(时间限制)以及-f(指定自定义脚本文件)。完整列表见下文。
选项
以下内容分为三个小节。数据库初始化和运行基准测试时使用不同的选项,但有些选项在这两种情况下都适用。
初始化选项
pgbench接受以下命令行初始化参数:
[-d]dbname[--dbname=]dbname-
指定要测试的数据库名称。如果未指定,则使用环境变量
PGDATABASE。如果未设置该变量,则使用连接指定的用户名。 -i--initialize-
进入初始化模式所必需。
-Iinit_steps--init-steps=init_steps-
仅执行正常初始化步骤中的选定部分。
init_steps指定要执行的初始化步骤,每个步骤用一个字符表示。各步骤会按照指定顺序调用。默认值为dtgvp。可用步骤如下:d(删除)-
删除任何现有的pgbench表。
t(创建表)-
创建标准pgbench场景使用的表,即
pgbench_accounts、pgbench_branches、pgbench_history和pgbench_tellers。 g或G(在客户端或服务器端生成数据)-
生成数据并将其装载到标准表中,替换其中任何已有数据。
使用
g(客户端生成数据)时,数据由pgbench客户端生成,再通过COPY发送到服务器,因此会大量占用客户端/服务器带宽。对于 14 及以上版本的PostgreSQL,pgbench会在普通(非分区)表上使用FREEZE选项装载数据,以加快后续的VACUUM。使用g时,在为所有表生成数据的过程中,每生成 100,000 行会输出一条日志消息。使用
G(服务器端生成数据)时,pgbench客户端只发送较小的查询,随后实际数据在服务器端生成。这种方式不需要大量带宽,但服务器会承担更多工作。使用G时,生成数据期间不会打印任何进度消息。默认初始化行为使用客户端生成数据(等同于
g)。 v(清理)-
在标准表上调用
VACUUM。 p(创建主键)-
在标准表上创建主键索引。
f(创建外键)-
在标准表之间创建外键约束。(请注意,默认情况下不执行此步骤。)
-Ffillfactor--fillfactor=fillfactor-
使用给定的 fillfactor 创建 pgbench_accounts、pgbench_tellers 和 pgbench_branches 表。默认值为 100。
-n--no-vacuum-
初始化期间不执行清理。(此选项会抑制 v 初始化步骤,即使 -I 中已指定该步骤。)
-q--quiet-
将日志切换为静默模式,每 5 秒只输出一条进度消息。默认日志每生成 100,000 行输出一条消息,因而往往会在每秒输出多行(尤其是在较好的硬件上)。
如果 -I 中指定了 G,此设置不生效。
-sscale_factor--scale=scale_factor-
将生成的行数乘以规模因子。例如,-s 100 会在 pgbench_accounts 表中创建 10,000,000 行。默认值为 1。当规模因子达到 20,000 或更大时,存放账户标识符的列(aid 列)会改用更大的整数类型(bigint),以容纳所需的账户标识符范围。
--foreign-keys-
在标准表之间创建外键约束。(如果初始化步骤序列中尚未包含
f步骤,则此选项会把它加入进去。) --index-tablespace=index_tablespace-
在指定的表空间中创建索引,而不是默认的表空间。
--partition-method=NAME-
使用 NAME 方法创建分区的 pgbench_accounts 表。可选值为 range 或 hash。此选项要求 --partitions 为非零值。未指定时默认为 range。
--partitions=NUM-
为按规模因子确定的账户数量创建具有 NUM 个分区的 pgbench_accounts 表,各分区大小大致相等。默认值为 0,表示不分区。
--tablespace=tablespace-
在指定的表空间中创建表,而不是默认的表空间。
--unlogged-tables-
将所有表创建为不记录 WAL 的表,而不是永久表。
基准测试选项
pgbench接受以下命令行基准测试参数:
-bscriptname[@weight]--builtin=scriptname[@weight]-
将指定的内置脚本添加到待执行脚本列表中。可用的内置脚本包括:
tpcb-like、simple-update和select-only。也接受内置名称的无歧义前缀。使用特殊名称list时,会显示内置脚本列表并立即退出。可以在 @ 后写入整数权重,以调整选择此脚本相对于其他脚本的概率。默认权重为 1。详情见下文。
-cclients--client=clients-
模拟的客户端数量,即并发数据库会话数。默认值为 1。
-C--connect-
为每个事务建立一个新连接,而不是仅在每个客户端会话中执行一次。这对于测量连接开销很有用。
-Dvarname=value--define=varname=value-
定义一个变量,供自定义脚本使用(见下文)。允许使用多个
-D选项。 -ffilename[@weight]--file=filename[@weight]-
将从
filename读取的事务脚本添加到要执行的脚本列表中。可以在 @ 后写入整数权重,以调整选择此脚本相对于其他脚本的概率。默认权重为 1。(如果脚本文件名包含 @ 字符,请追加权重以消除歧义,例如 filen@me@1。)详情见下文。
-jthreads--jobs=threads-
pgbench 内部的工作线程数。在多 CPU 机器上,使用多个线程可能有帮助。客户端会尽可能均匀地分配到可用线程中。默认值为 1。
-l--log-
将每个事务的信息写入日志文件。详情见下文。
-Llimit--latency-limit=limit-
持续时间超过
limit毫秒的事务会被单独计数和报告,称为late。使用限流(
--rate=...)时,若某个事务落后于计划时间超过limit毫秒,从而已经不可能满足延迟限制,则它根本不会被发送到服务器。此类事务会被单独计数并报告为skipped。使用
--max-tries选项时,若某个事务因串行化异常或死锁而失败,且其所有尝试的总耗时大于limit毫秒,则不会再重试。若只想限制尝试总时间而不限制尝试次数,请使用--max-tries=0。默认情况下,--max-tries为 1,出现串行化/死锁错误的事务不会重试。有关此类事务重试的更多信息,见失败和串行化/死锁重试。 -Mquerymode--protocol=querymode-
用于向服务器提交查询的协议:
-
simple:使用简单查询协议。 -
extended:使用扩展查询协议。 -
prepared:使用带有预备语句的扩展查询协议。
在
prepared模式下,pgbench 从第二次查询迭代开始复用解析分析结果,因此pgbench 比其他模式运行得更快。默认值是简单查询协议。(更多信息见第 54 章。)
-
-n--no-vacuum-
在运行测试前不执行任何清理。如果运行的是不包含标准表
pgbench_accounts、pgbench_branches、pgbench_history和pgbench_tellers的自定义测试场景,则此选项是必需的。 -N--skip-some-updates-
运行内置的 simple-update 脚本。是
-b simple-update的简写。 -Psec--progress=sec-
每
sec秒显示一次进度报告。报告包括自运行开始以来的时间、自上次报告以来的 TPS、自上次报告以来事务延迟的平均值和标准差,以及失败事务数。使用限流(-R)时,延迟是相对于事务计划开始时间计算的,而不是实际开始时间,因此其中也包含平均计划滞后时间。当使用--max-tries启用事务在串行化/死锁错误后的重试时,报告还会包含发生过重试的事务数以及总重试次数。 -r--report-per-command-
基准测试结束后,为每条命令报告以下统计信息:每条语句的平均延迟(从客户端角度衡量的执行时间)、失败次数,以及该命令发生序列化错误或死锁后的重试次数。只有 --max-tries 选项不等于 1 时,报告才会显示重试统计。
-Rrate--rate=rate-
以指定速率执行事务,而不是像默认行为那样尽可能快地运行。速率以每秒事务数表示。如果目标速率高于可达到的最大速率,则速率限制不会影响结果。
该速率通过让事务沿着一条符合泊松分布的时间线启动来实现。预期开始时间表是根据客户端首次启动的时间向前推进的,而不是根据前一个事务结束的时间。这意味着,当某些事务超过其原定结束时间时,后续事务仍有可能重新赶上计划。
启用限流后,运行结束时报告的事务延迟是从计划开始时间计算的,因此它包含每个事务等待前一个事务完成的时间。这段等待时间称为计划滞后时间,其平均值和最大值也会单独报告。若要得到相对于事务实际开始时间的延迟,也就是事务在数据库中实际执行所花费的时间,可以用报告中的延迟减去计划滞后时间。
如果同时使用
--latency-limit和--rate,一个事务可能会落后太多,以至于在前一个事务结束时已经超过了延迟限制,因为延迟是从计划开始时间计算的。这样的事务不会发送到服务器,而是完全跳过并单独计数。较高的计划滞后时间表明,在所选客户端数和线程数下,系统无法以指定速率处理事务。当平均事务执行时间长于事务之间的计划间隔时,后续事务会不断进一步落后,而计划滞后时间也会随着测试持续时间增加。在这种情况下,需要降低指定的事务速率。
-sscale_factor--scale=scale_factor-
在pgbench输出中报告指定的比例因子。对于内置测试,这没有必要;系统会通过统计
pgbench_branches表中的行数来检测正确的比例因子。但在只测试自定义基准(-f选项)时,除非使用此选项,否则比例因子会被报告为 1。 -S--select-only-
运行内置的 select-only 脚本。是
-b select-only的简写。 -ttransactions--transactions=transactions-
每个客户端运行的事务数量。默认值为10。
-Tseconds--time=seconds-
让测试运行指定的秒数,而不是让每个客户端执行固定数量的事务。
-t和-T是互斥的。 -v--vacuum-all-
在运行测试之前,对四个标准表全部执行清理。如果既不使用
-n也不使用-v,pgbench会对pgbench_tellers和pgbench_branches表进行清理,并截断pgbench_history。 --aggregate-interval=seconds-
聚合间隔的长度(以秒为单位)。只能与
-l选项一起使用。使用此选项时,日志包含每个间隔的摘要数据,如下所述。 --exit-on-abort-
当任一客户端因错误被中止时,立即退出。如果不指定该选项,即使某个客户端被中止,其他客户端仍可按
-t或-T的设定继续运行,此时pgbench会输出不完整的结果。请注意,串行化失败或死锁失败不会中止客户端,因此不受该选项影响。更多信息见失败和串行化/死锁重试。
--failures-detailed-
在逐事务日志、聚合日志以及主报告和逐脚本报告中,按以下类型分组报告失败:
-
串行化失败;
-
死锁失败;
更多信息见失败和串行化/死锁重试。
-
--log-prefix=prefix-
设置由
--log创建的日志文件的文件名前缀。默认值为pgbench_log。 --max-tries=number_of_tries-
为发生序列化错误或死锁的事务启用重试,并设置最大尝试次数。此选项可以与 --latency-limit 一起使用,后者限制同一事务所有尝试的总耗时;此外,只有指定 --latency-limit 或 --time,才允许使用无限尝试次数(--max-tries=0)。默认值为 1,发生序列化错误或死锁的事务不会重试。有关此类事务重试的更多信息,参见“失败与序列化/死锁重试”。
--progress-timestamp-
显示进度(选项
-P)时,使用时间戳(Unix 纪元)而不是自运行开始以来的秒数。单位为秒,小数点后精确到毫秒。这有助于比较各种工具生成的日志。 --random-seed=seed-
设置随机数生成器种子。它会先为系统随机数生成器设种,再生成一系列初始生成器状态,每个线程一个。
seed的取值可以是:time(默认值,种子基于当前时间),rand(使用强随机源,如果没有可用的则失败),或者无符号十进制整数值。随机生成器既可以在 pgbench 脚本中显式调用(random...函数),也可以隐式调用(例如选项--rate用于调度事务)。显式设置时,实际用于设种的值会显示在终端上。任何允许的seed值也可以通过环境变量PGBENCH_RANDOM_SEED提供。为确保提供的种子影响所有可能的用途,将此选项放在第一位或使用环境变量。显式设置种子可以在随机数层面精确复现一次
pgbench运行。由于随机状态按线程管理,这意味着对于相同的调用,如果每个线程只有一个客户端,且不存在外部依赖或数据依赖,那么pgbench运行可以完全一致。从统计角度看,精确复现实验并不是好主意,因为它可能掩盖性能波动,甚至不恰当地提高性能,例如反复命中与前一次运行相同的页面。不过,这对调试也可能非常有帮助,例如重现会触发错误的棘手案例。请谨慎使用。 --sampling-rate=rate-
写入日志时使用的采样率,用于减少生成的日志量。如果给定此选项,则只记录指定比例的事务。1.0 表示记录全部事务,0.05 表示只记录 5% 的事务。
处理日志文件时,记得把采样率考虑进去。例如,计算 TPS 值时,需要按采样率对数字进行相应换算(例如采样率为 0.01 时,只能得到实际 TPS 的 1/100)。
--show-script=scriptname-
将内置脚本
scriptname的实际代码输出到 stderr,然后立即退出。 --verbose-errors-
打印关于所有错误和失败(不再重试的错误)的消息,包括超出了哪一种重试限制,以及对于串行化/死锁失败超出的幅度。(请注意,这种情况下输出量可能会显著增加。)更多信息见失败和串行化/死锁重试。
公共选项
pgbench 还接受以下用于连接参数及其他通用设置的命令行参数:
--debug-
打印调试输出。
-hhostname--host=hostname-
数据库服务器的主机名。
-pport--port=port-
数据库服务器的端口号。
-Ulogin--username=login-
连接时使用的用户名。
-V--version-
打印pgbench版本并退出。
-?--help-
显示pgbench命令行参数的帮助信息并退出。
退出状态
成功运行时退出状态为 0。退出状态 1 表示静态问题,例如无效的命令行选项,或者本不应发生的内部错误。基准测试启动阶段的早期错误,例如初始连接失败,也会以状态 1 退出。运行期间的错误,例如数据库错误或脚本问题,会导致退出状态为 2。在后一种情况下,如果没有指定 --exit-on-abort 选项,pgbench 会打印部分结果。
环境
PGDATABASEPGHOSTPGPORTPGUSER-
默认连接参数。
与大多数其他PostgreSQL工具一样,此工具也使用libpq支持的环境变量(见第 32.15 节)。
环境变量PG_COLOR指定是否在诊断消息中使用颜色。可能的值为always、auto和never。
注解
在pgbench中实际执行的“事务”是什么?
pgbench会从指定列表中随机选取测试脚本来执行。这些脚本既可以是用-b指定的内置脚本,也可以是用-f指定的用户脚本。每个脚本都可以在其后加上一个以@引出的相对权重,以改变其被选中的概率。默认权重为1。权重为0的脚本会被忽略。
默认的内置事务脚本(也可通过-b tpcb-like调用)会针对随机选取的aid、tid、bid和delta在每个事务中发出七条命令。该场景受 TPC-B 基准启发,但并不是真正的 TPC-B,因此才取了这个名字。
-
BEGIN; -
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; -
SELECT abalance FROM pgbench_accounts WHERE aid = :aid; -
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; -
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; -
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); -
END;
如果选择simple-update内置脚本(也就是-N),事务中将不包含第 4 步和第 5 步。这会避免在这些表上发生更新争用,但也会让该测试场景更不像 TPC-B。
如果选择select-only内置脚本(也就是-S),则只执行SELECT。
自定义脚本
pgbench支持自定义基准测试场景:只需用从文件中读取的事务脚本(-f选项)替换默认事务脚本(见上文)即可。在这种情况下,一个“事务”就表示脚本文件的一次执行。
脚本文件包含一个或多个以分号结束的 SQL 命令。空行以及以--开头的行会被忽略。脚本文件还可以包含“元命令”,它们由pgbench自身解释,详见下文。
注意
在PostgreSQL 9.6 之前,脚本文件中的 SQL 命令以换行结束,因此不能跨行。现在连续 SQL 命令之间必须用分号分隔(如果 SQL 命令后面跟着一个元命令,则不需要分号)。如果需要创建一个既能在旧版也能在新版pgbench下工作的脚本文件,务必将每个 SQL 命令写在单独一行,并以分号结束。
假定pgbench脚本不包含不完整的 SQL 事务块。如果在运行时客户端在尚未完成最后一个事务块时就到达脚本末尾,该客户端将被中止。
脚本文件提供了一种简单的变量替换机制。变量名必须由字母(包括非拉丁字母)、数字和下划线组成,并且首字符不能是数字。如上所述,变量可以用命令行-D选项设置,也可以用下文介绍的元命令设置。除了通过-D命令行选项预先设置的变量之外,还有少量变量会被自动预设,列在表 301中。如果使用-D为这些变量指定值,则会覆盖自动预设值。一旦设置好变量,就可以在 SQL 命令中写:variablename来插入其值。当运行多个客户端会话时,每个会话都有自己的变量集合。pgbench在单条语句中最多支持 255 次变量使用。
表 301. pgbench 自动变量
| 变量 | 说明 |
|---|---|
client_id |
标识客户端会话的唯一编号(从零开始) |
default_seed |
默认在 hash 和伪随机置换函数中使用的种子 |
random_seed |
随机数生成器种子(除非被-D覆盖) |
scale |
当前比例因子 |
脚本文件中的元命令以反斜线(\)开头,通常延伸到行尾,不过也可以通过写反斜线换行继续到后续行。元命令的参数以空白分隔。支持的元命令如下:
\gset [prefix]\aset [prefix]-
这些命令可用于结束 SQL 查询,以代替结尾分号(
;)。使用
\gset命令时,前面的 SQL 查询预期返回一行,其各列会被存入以列名命名的变量;如果提供了prefix,则会加上该前缀。使用
\aset命令时,所有组合 SQL 查询(由\;分隔)的列都会被存入以列名命名的变量中;如果提供了prefix,则会加上该前缀。如果查询不返回任何行,则不会进行赋值,可以通过测试变量是否存在来检测这种情况。如果查询返回多行,则保留最后一个值。\gset和\aset不能用在管道模式,因为在命令需要它们的时候,查询结果还不可用。下面的示例将第一个查询中的最终账户余额放入变量
abalance,并用第三个查询中的整数填充变量p_two和p_three。第二个查询的结果会被丢弃。最后两个组合查询的结果会被存入变量four和five。UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid RETURNING abalance \gset -- compound of two queries SELECT 1 \; SELECT 2 AS two, 3 AS three \gset p_ SELECT 4 AS four \; SELECT 5 AS five \aset
\ifexpression\elifexpression\else\endif-
这一组命令实现了可嵌套的条件块,类似于
psql中的\ifexpression。条件表达式与\set中的表达式相同,非零值会被解释为真。 \setvarnameexpression-
将变量
varname设置为根据expression计算出的值。该表达式可以包含NULL常量、布尔常量TRUE和FALSE、5432这样的整数常量、3.14159这样的双精度常量、对变量的引用:variablename、操作符(保留其通常的 SQL 优先级和结合性)、函数调用、SQLCASE通用条件表达式以及括号。函数和大部分操作符在
NULL输入上会返回NULL。就条件判断而言,非零数值为
TRUE,零值和NULL为FALSE。过大或过小的整数和双精度常量,以及整数算术操作符(
+、-、*和/)都会在溢出时引发错误。如果 CASE 没有最后的 ELSE 子句,则默认值为 NULL。
示例:
\set ntellers 10 * :scale \set aid (1021 * random(1, 100000 * :scale)) % \ (100000 * :scale) + 1 \set divx CASE WHEN :x <> 0 THEN :y/:x ELSE NULL END \sleepnumber[ us | ms | s ]-
让脚本执行休眠指定时长,单位可以是微秒(
us)、毫秒(ms)或秒(s)。如果省略单位,则默认为秒。number可以是整数常量,也可以是引用了整数值变量的:variablename。示例:
\sleep 10 ms
\setshellvarnamecommand[argument... ]-
将变量
varname设置为 shell 命令command在给定argument参数下的结果。该命令必须通过标准输出返回一个整数值。command和每个argument都可以是文本常量,也可以是引用某个变量的:variablename。如果要使用以冒号开头的argument,请在argument开头再写一个冒号。示例:
\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
\shellcommand[argument... ]-
与
\setshell相同,但命令结果会被丢弃。示例:
\shell command literal_argument :variable ::literal_starting_with_colon
\startpipeline\syncpipeline\endpipeline-
这组命令用于实现 SQL 语句的管道执行。管道必须以
\startpipeline开始,并以\endpipeline结束;在两者之间可以出现任意数量的\syncpipeline,它会发送一个sync 消息,既不会结束当前管道,也不会刷新发送缓冲区。在管道模式下,语句会发送到服务器,而不等待前一条语句的结果。更多细节见第 32.5 节。管道模式要求使用扩展查询协议。
内置操作符
表 302中列出的算术、按位、比较和逻辑操作符都内置于pgbench中,可用于\set中的表达式。这些操作符按优先级从低到高列出。除非另有说明,接受两个数字输入的操作符只要任一输入为双精度,就会产生双精度结果;否则产生整数结果。
表 302. pgbench 操作符
|
操作符 描述 示例 |
|
|---|---|
|
逻辑或
|
|
|
逻辑与
|
|
|
逻辑非
|
|
|
布尔值测试
|
|
|
空值测试
|
|
|
等于
|
|
|
不等于
|
|
|
不等于
|
|
|
小于
|
|
|
小于等于
|
|
|
大于
|
|
|
大于等于
|
|
|
按位或
|
|
|
按位异或
|
|
|
按位与
|
|
|
按位非
|
|
|
按位左移
|
|
|
按位右移
|
|
|
加法
|
|
|
减法
|
|
|
乘法
|
|
|
除法(如果两个输入都是整数,则将结果向零截断)
|
|
|
模(余数)
|
|
|
取相反数
|
内置函数
表 303中列出的函数都内置于pgbench,可用于\set中的表达式。
表 303. pgbench 函数
|
函数 描述 示例 |
|
|---|---|
|
绝对值
|
|
|
将参数打印到stderr,并返回参数。
|
|
|
转换为 double。
|
|
|
指数函数(
|
|
|
选择参数中的最大值。
|
|
|
这是
|
|
|
计算 FNV-1a hash。
|
|
|
计算 MurmurHash2 hash。
|
|
|
转换为 integer。
|
|
|
选择参数中的最小值。
|
|
|
自然对数
|
|
|
模(余数)
|
|
|
|
|
|
π的近似值
|
|
|
|
|
|
计算
|
|
|
计算
|
|
|
计算
|
|
|
计算
|
|
|
平方根
|
random函数使用均匀分布生成值,也就是说,指定范围内的所有值都以相同概率被抽取。random_exponential、random_gaussian和random_zipfian函数则需要额外提供一个 double 参数,用来确定分布的精确形状。
-
对于指数分布,
parameter通过在parameter处截断一个快速衰减的指数分布,再将其投影到边界之间的整数上,从而控制分布。准确地说,令
f(x) = exp(-parameter * (x - min) / (max - min + 1)) / (1 - exp(-parameter))然后,以 f(i) - f(i + 1) 的概率抽取 min 到 max 范围内(含两端)的值 i。
直观地说,parameter 越大,越频繁地访问接近 min 的值,而越少访问接近 max 的值。parameter 越接近 0,访问分布就越平坦(更均匀)。对此分布的粗略近似是:范围内最常访问、接近 min 的 1% 的值,占 parameter% 的抽取次数。parameter 必须严格为正值。
-
对于高斯分布,该区间会映射到一个标准正态分布(经典钟形高斯曲线),并在左侧
-parameter和右侧+parameter处截断。区间中部的值更容易被抽到。准确地说,如果PHI(x)是标准正态分布的累积分布函数,均值mu定义为(max + min) / 2.0,则有
f(x) = PHI(2.0 * parameter * (x - mu) / (max - min + 1)) /
(2.0 * PHI(parameter) - 1)然后,以 f(i + 0.5) - f(i - 0.5) 的概率抽取 min 到 max 范围内(含两端)的值 i。直观地说,parameter 越大,越频繁地抽取接近区间中部的值,而越少抽取接近 min 和 max 边界的值。大约 67% 的值取自区间中部的 1.0 / parameter 部分,即均值两侧各占相对宽度 0.5 / parameter 的范围;95% 的值取自中部的 2.0 / parameter 部分,即均值两侧各占相对宽度 1.0 / parameter 的范围。例如,parameter 为 4.0 时,67% 的值取自区间中部的四分之一(1.0 / 4.0),即从 3.0 / 8.0 到 5.0 / 8.0;95% 的值取自区间中部的一半(2.0 / 4.0),即第二和第三四分位区间。parameter 允许的最小值为 2.0。
-
random_zipfian 生成有界齐普夫分布。parameter 定义分布的偏斜程度。parameter 越大,越频繁地抽取接近区间起点的值。此分布具有以下性质:假设范围从 1 开始,抽取 k 与抽取 k+1 的概率之比为 ((k+1)/k)**parameter。例如,random_zipfian(1, ..., 2.5) 生成值 1 的频率约为生成值 2 的 (2/1)**2.5 = 5.66 倍,而后者的生成频率又约为生成值 3 的 (3/2)**2.5 = 2.76 倍,依此类推。
pgbench 的实现基于 Luc Devroye 的《Non-Uniform Random Variate Generation》,第 550–551 页,Springer,1986 年。由于该算法的限制,parameter 的取值限制在 [1.001, 1000] 范围内。
注意
在设计以非均匀方式选择行的基准测试时,要注意被选中的行可能与其他数据相关,例如与序列生成的 ID 或物理行顺序相关,这可能会扭曲性能测量结果。
为避免这一点,可以使用permute函数,或采用其他具有类似效果的额外步骤,对选中的行进行打乱并移除此类相关性。
Hash 函数hash、hash_murmur2和hash_fnv1a都接受一个输入值和一个可选的种子参数。如果没有提供种子,则会使用:default_seed的值;除非通过命令行-D选项覆盖,否则该值会被随机初始化。
permute 接受输入值、大小和可选的种子参数。它在 [0, size) 范围内生成整数的伪随机排列,并返回输入值在排列中的索引。所选排列由种子决定,未指定种子时默认使用 :default_seed。与哈希函数不同,permute 保证输出值既无冲突也无空缺。区间外的输入值会对 size 取模。如果 size 不是正数,函数会报错。permute 可用于打散 random_zipfian 或 random_exponential 等非均匀随机函数的分布,使更频繁抽取的值不会存在简单的关联。例如,以下 pgbench 脚本模拟了社交媒体和博客平台上可能出现的一类典型实际负载:少数账户产生过量负载。
\set size 1000000 \set r random_zipfian(1, :size, 1.07) \set k 1 + permute(:r, :size)
在某些情况下,需要若干彼此不相关的不同分布,这时可选种子参数就很有用:
\set k1 1 + permute(:r, :size, :default_seed + 123) \set k2 1 + permute(:r, :size, :default_seed + 321)
也可以用hash近似实现类似的行为:
\set size 1000000 \set r random_zipfian(1, 100 * :size, 1.07) \set k 1 + abs(hash(:r)) % :size
但是,由于hash会产生冲突,有些值将永远不可达,而另一些值则会比原始分布所预期的更常出现。
作为一个示例,内置的类 TPC-B 事务的全部定义是:
\set aid random(1, 100000 * :scale) \set bid random(1, 1 * :scale) \set tid random(1, 10 * :scale) \set delta random(-5000, 5000) BEGIN; UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; SELECT abalance FROM pgbench_accounts WHERE aid = :aid; UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); END;
该脚本允许事务的每次迭代都引用不同的随机选中行。(这个示例也说明了为什么每个客户端会话都必须拥有自己的变量 — 否则它们就无法彼此独立地访问不同的行。)
逐事务日志记录
使用 -l 选项(但不使用 --aggregate-interval)时,pgbench 会将每个事务的信息写入日志文件。日志文件名为 prefix.nnn,其中 prefix 默认为 pgbench_log,nnn 是 pgbench 进程的 PID。可以通过 --log-prefix 选项修改前缀。如果 -j 选项为 2 或更大,即存在多个工作线程,每个线程都有自己的日志文件。第一个工作线程的日志命名与通常的单工作线程情况相同。其余工作线程的日志文件名为 prefix.nnn.mmm,其中 mmm 是从 1 开始的工作线程序号。
日志文件的每一行描述一个事务。它包含以下以空格分隔的字段:
client_id-
标识运行事务的客户端会话
transaction_no-
统计该会话已执行的事务数量
time-
事务耗时,单位为微秒
script_no-
标识该事务所使用的脚本文件(当通过
-f或-b指定多个脚本时很有用) time_epoch-
事务完成时间,以 Unix 纪元时间戳表示
time_us-
事务完成时间的小数秒部分,以微秒为单位
schedule_lag-
事务开始延迟,即事务计划开始时间与实际开始时间之间的差值,单位为微秒(仅在指定
--rate时出现) retries-
事务执行期间发生序列化错误或死锁后的重试次数(仅当 --max-tries 不等于一时出现)
当同时使用--rate和--latency-limit时,跳过事务的time将被报告为skipped。如果事务以失败结束,其time将被报告为failed。如果使用--failures-detailed选项,失败事务的time会根据失败类型报告为serialization或deadlock(详见失败和串行化/死锁重试)。
这里是在单个客户端运行中生成的一个日志文件的片段:
0 199 2241 0 1175850568 995598 0 200 2465 0 1175850568 998079 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663
另一个示例使用的是--rate=100以及--latency-limit=5(注意额外的 schedule_lag列):
0 81 4621 0 1412881037 912698 3005 0 82 6173 0 1412881037 914578 4304 0 83 skipped 0 1412881037 914578 5217 0 83 skipped 0 1412881037 914578 5099 0 83 4722 0 1412881037 916203 3108 0 84 4142 0 1412881037 918023 2333 0 85 2465 0 1412881037 919759 740
在这个示例中,事务 82 迟到了,因为它的延迟(6.173 ms)超过了 5 ms 限制。接下来的两个事务被跳过,因为它们在开始之前就已经迟到了。
以下示例展示了包含失败与重试的日志片段,最大尝试次数设为 10(注意额外的 retries 列):
3 0 47423 0 1499414498 34501 3 3 1 8333 0 1499414498 42848 0 3 2 8358 0 1499414498 51219 0 4 0 72345 0 1499414498 59433 6 1 3 41718 0 1499414498 67879 4 1 4 8416 0 1499414498 76311 0 3 3 33235 0 1499414498 84469 3 0 0 failed 0 1499414498 84905 9 2 0 failed 0 1499414498 86248 9 3 4 8307 0 1499414498 92788 0
如果使用--failures-detailed选项,失败的类型将在time中报告,如下所示:
3 0 47423 0 1499414498 34501 3 3 1 8333 0 1499414498 42848 0 3 2 8358 0 1499414498 51219 0 4 0 72345 0 1499414498 59433 6 1 3 41718 0 1499414498 67879 4 1 4 8416 0 1499414498 76311 0 3 3 33235 0 1499414498 84469 3 0 0 serialization 0 1499414498 84905 9 2 0 serialization 0 1499414498 86248 9 3 4 8307 0 1499414498 92788 0
在能够处理大量事务的硬件上运行长时间测试时,日志文件可能会变得非常大。可以使用--sampling-rate选项,仅记录事务的随机样本。
聚合日志记录
使用--aggregate-interval选项时,日志文件会采用不同的格式。每一行日志描述一个聚合时间间隔,包含以下以空格分隔的字段:
interval_start-
该时间间隔的起始时间,以 Unix 纪元时间戳表示
num_transactions-
该时间间隔内的事务数
sum_latency-
事务延迟的总和
sum_latency_2-
事务延迟的平方和
min_latency-
最小事务延迟
max_latency-
最大事务延迟
sum_lag-
事务开始延迟的总和(除非指定了
--rate,否则为零) sum_lag_2-
事务开始延迟的平方和(除非指定了
--rate,否则为零) min_lag-
最小事务开始延迟(除非指定了
--rate,否则为零) max_lag-
最大事务开始延迟(除非指定了
--rate,否则为零) skipped-
因为启动时间会太晚而被跳过的事务数(除非指定了
--rate和--latency-limit,否则为零) retried-
发生重试的事务数(--max-tries 等于一时为零)
retries-
发生序列化错误或死锁后的重试次数(--max-tries 等于一时为零)
serialization_failures-
发生串行化错误且其后未再重试的事务数(除非指定了
--failures-detailed,否则为零) deadlock_failures-
发生死锁错误且其后未再重试的事务数(除非指定了
--failures-detailed,否则为零)
下面是使用该选项生成的示例输出:
pgbench --aggregate-interval=10 --time=20 --client=10 --log --rate=1000 --latency-limit=10 --failures-detailed --max-tries=10 test
1650260552 5178 26171317 177284491527 1136 44462 2647617 7321113867 0 9866 64 7564 28340 4148 0
1650260562 4808 25573984 220121792172 1171 62083 3037380 9666800914 0 9998 598 7392 26621 4527 0
请注意,普通(未聚合)日志格式会显示每个事务所使用的脚本,而聚合格式不会。因此,如果需要按脚本区分的数据,就必须自行聚合。
逐语句报告
使用-r选项,pgbench为每个语句收集以下统计信息:
-
latency— 每条语句的耗时。pgbench报告该语句所有成功执行的平均值。 -
该语句的失败次数。更多信息请参见失败和串行化/死锁重试。
-
该语句因串行化或死锁错误而发生的重试次数。更多信息请参见失败和串行化/死锁重试。
报告仅在--max-tries选项不等于1时显示重试统计信息。
所有数值都是针对每个客户端执行的每条语句计算的,并在基准测试完成后报告。
对于默认脚本,输出将类似如下:
starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 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%) number of transactions above the 50.0 ms latency limit: 1311/10000 (13.110 %) latency average = 28.488 ms latency stddev = 21.009 ms initial connection time = 69.068 ms tps = 346.224794 (without initial connection time) statement latencies in milliseconds and failures: 0.012 0 \set aid random(1, 100000 * :scale) 0.002 0 \set bid random(1, 1 * :scale) 0.002 0 \set tid random(1, 10 * :scale) 0.002 0 \set delta random(-5000, 5000) 0.319 0 BEGIN; 0.834 0 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.641 0 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 11.126 0 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 12.961 0 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.634 0 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.957 0 END;
使用可串行化默认事务隔离级别的默认脚本的另一个输出示例(PGOPTIONS='-c default_transaction_isolation=serializable' pgbench ...):
starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 query mode: simple number of clients: 10 number of threads: 1 maximum number of tries: 10 number of transactions per client: 1000 number of transactions actually processed: 6317/10000 number of failed transactions: 3683 (36.830%) number of transactions retried: 7667 (76.670%) total number of retries: 45339 number of transactions above the 50.0 ms latency limit: 106/6317 (1.678 %) latency average = 17.016 ms latency stddev = 13.283 ms initial connection time = 45.017 ms tps = 186.792667 (without initial connection time) statement latencies in milliseconds, failures and retries: 0.006 0 0 \set aid random(1, 100000 * :scale) 0.001 0 0 \set bid random(1, 1 * :scale) 0.001 0 0 \set tid random(1, 10 * :scale) 0.001 0 0 \set delta random(-5000, 5000) 0.385 0 0 BEGIN; 0.773 0 1 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.624 0 0 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 1.098 320 3762 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 0.582 3363 41576 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.465 0 0 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.933 0 0 END;
如果指定了多个脚本文件,则会分别为每个脚本文件报告所有统计信息。
注意,为逐语句延迟计算收集额外的计时信息会带来一定开销。这会拖慢平均执行速度,并降低计算出的 TPS。减速幅度在很大程度上取决于平台和硬件。比较启用和未启用延迟报告时的平均 TPS 值,是判断这一计时开销是否显著的好方法。
失败和串行化/死锁重试
在执行pgbench时,有三种主要类型的错误:
-
主程序错误。它们最为严重,总是会导致pgbench立即退出,并显示相应的错误消息。它们包括:
-
pgbench开始执行时的错误(例如选项值无效);
-
初始化模式中的错误(例如,用于创建内置脚本所需表的查询失败);
-
在线程启动之前发生的错误(例如无法连接到数据库服务器、元命令中有语法错误、线程创建失败);
-
内部pgbench错误(理论上永远不该发生……)。
-
-
线程在管理其客户端时发生的错误(例如,客户端无法开始连接数据库服务器,或客户端连接数据库服务器所用的套接字已经失效)。在这种情况下,该线程的所有客户端都会停止,而其他线程继续工作;但是,如果指定了
--exit-on-abort,则所有线程都会立即停止。 -
直接客户端错误。在发生内部pgbench错误(理论上不应发生)或指定了
--exit-on-abort时,它们会导致pgbench立即退出并显示相应错误消息。否则,最坏情况下只会中止失败的客户端,而其他客户端继续运行(但某些客户端错误会在不中止客户端的情况下处理并单独报告,见下文)。本节后续默认讨论的都是直接客户端错误,而不是内部pgbench错误。
客户端在发生严重错误时会中止运行;例如,与数据库服务器的连接丢失,或者脚本在最后一个事务尚未完成时就结束了。另外,如果 SQL 或元命令执行失败,且原因不是串行化或死锁错误,客户端也会中止。否则,如果 SQL 命令因串行化或死锁错误而失败,客户端不会中止。在这种情况下,当前事务会回滚,也包括将客户端变量设置为此事务运行之前的状态(假设一个事务脚本只包含一个事务;详见在 pgbench 中实际执行的“事务”是什么?了解更多信息)。发生串行化或死锁错误的事务会在回滚后重新执行,直到成功完成,或者达到最大尝试次数(由--max-tries指定)、达到最大重试时间(由--latency-limit指定),或者基准测试结束(由--time指定)。如果最后一次尝试仍然失败,该事务会被报告为失败,但客户端不会中止,而是继续工作。
注意
如果未指定 --max-tries 选项,事务在发生序列化错误或死锁后不会重试,因为其默认值为 1。可以使用无限尝试次数(--max-tries=0)并配合 --latency-limit,仅限制尝试的最长总耗时。使用无限尝试次数时,也可以通过 --time 限制基准测试时长。
在重复包含多个事务的脚本时要小心:脚本总是完全重试,因此成功的事务可能会执行多次。
使用 shell 命令重试事务时要小心。与 SQL 命令的结果不同,shell 命令的结果不会回滚,唯一的例外是\setshell命令设置的变量值。
成功事务的延迟包括事务执行的整个时间,包括回滚和重试。延迟仅针对成功的事务和命令进行测量,而不针对失败的事务或命令。
主报告包含失败事务的数量。如果 --max-tries 选项不等于 1,主报告还会包含重试相关统计:发生重试的事务总数和重试总次数。每脚本报告继承主报告的所有这些字段。只有 --max-tries 选项不等于 1 时,每语句报告才会显示重试统计。
如果希望在逐事务日志、聚合日志以及主报告和逐脚本报告中按基本类型对失败进行分组,请使用--failures-detailed选项。如果还希望按类型区分所有错误和失败(不再重试的错误),包括超出了哪一种重试限制,以及串行化/死锁失败超出了多少,请使用--verbose-errors选项。
表访问方法
可以为 pgbench 表指定表访问方法。环境变量PGOPTIONS用于指定通过命令行传递给 PostgreSQL 的数据库配置选项(见第 19.1.4 节)。例如,可以用如下方式为 pgbench 创建的表指定一个名为wuzza的假想默认表访问方法:
PGOPTIONS='-c default_table_access_method=wuzza'
良好实践
很容易用pgbench得出完全没有意义的数字。下面给出一些有助于获得有用结果的准则。
首先,绝不要相信任何只运行了几秒钟的测试。使用-t或-T选项让测试至少持续几分钟,以便平滑掉噪声。在某些情况下,可能需要数小时才能得到可复现的结果。一个好做法是把同一测试运行几次,看看结果是否可复现。
对于默认的类 TPC-B 测试场景,初始化规模因子(-s)应至少与计划测试的最大客户端数量(-c)一样大,否则测量的主要是更新争用。pgbench_branches 表只有 -s 行,而每个事务都要更新其中一行,因此 -c 大于 -s 必然会导致大量事务阻塞,等待其他事务完成。
默认测试场景还会对表初始化后的时间长短非常敏感:表中死元组和无效空间的累积会改变结果。要理解这些结果,必须跟踪更新总数以及何时发生清理。如果启用了自动清理,它可能会给测得的性能带来不可预测的变化。
pgbench的一个局限是:在尝试测试大量客户端会话时,它自己也可能成为瓶颈。可以通过在与数据库服务器不同的机器上运行pgbench来缓解这一点,不过网络延迟必须足够低。甚至可以在多台客户端机器上同时运行多个pgbench实例,对同一台数据库服务器施压。
安全性
如果不受信任的用户能够访问尚未采用模式的安全使用方式的数据库,就不要在该数据库中运行pgbench。pgbench使用非限定名称,并且不会更改搜索路径。
文档与源码
来源构建
- 版本
- 18.6
- 构建
- https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2
- 来源指纹
ee8d1a3612338fd9adf250730cb640fcc5233b5491337cc00a316a44e3a0b9f8
版本比较
PostgreSQL 10 → 11: 属性变化。
以下差异保留原始字段名与英文源描述。
--- PostgreSQL 10
+++ PostgreSQL 11
@@ -10,6 +10,14 @@
"signature": "-i --initialize"
},
{
+ "description": "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 (Generate data) Generate data and load it into the standard tables, replacing any data already present. 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.)",
+ "names": [
+ "-I init_steps",
+ "--init-steps= init_steps"
+ ],
+ "signature": "-I init_steps --init-steps= init_steps"
+ },
+ {
"description": "Create the pgbench_accounts , pgbench_tellers and pgbench_branches tables with the given fillfactor. Default is 100.",
"names": [
"-F",
@@ -18,7 +26,7 @@
"signature": "-F fillfactor --fillfactor= fillfactor"
},
{
- "description": "Perform no vacuuming after initialization.",
+ "description": "Perform no vacuuming during initialization. (This option suppresses the v initialization step, even if it was specified in -I .)",
"names": [
"-n",
"--no-vacuum"
@@ -42,7 +50,7 @@
"signature": "-s scale_factor --scale= scale_factor"
},
{
- "description": "Create foreign key constraints between the standard tables.",
+ "description": "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.)",
"names": [
"--foreign-keys"
],
@@ -142,7 +150,7 @@
"signature": "-L limit --latency-limit= limit"
},
{
- "description": "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. The default is simple query protocol. (See Chapter 52 for more information.)",
+ "description": "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. The default is simple query protocol. (See Chapter 53 for more information.)",
"names": [
"-M",
"--protocol="
@@ -166,7 +174,7 @@
"signature": "-N --skip-some-updates"
},
{
- "description": "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 and standard deviation 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.",
+ "description": "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 and standard deviation 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.",
"names": [
"-P",
"--progress="
@@ -251,7 +259,14 @@
"signature": "--progress-timestamp"
},
{
- "description": "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).",
+ "description": "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.",
+ "names": [
+ "--random-seed="
+ ],
+ "signature": "--random-seed= SEED"
+ },
+ {
+ "description": "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).",
"names": [
"--sampling-rate= rate"
],
比较已记录的接口与属性,排除来源指纹和构建元数据。某个样本中没有记录,不能据此判断实际引入或移除的版本。
相关条目
导出 JSON · 返回命令行工具 · 收录范围为 PostgreSQL 10 至 20;最早采样版本不一定是实际引入版本。