pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
pgbench是一个用于对PostgreSQL执行基准测试的简单程序。它会反复执行同一组 SQL 命令,也可在多个并发数据库会话中运行,然后计算平均事务速率(每秒事务数)。默认情况下,pgbench测试的是一个大体上基于 TPC-B 的场景,每个事务包含五条SELECT、UPDATE和INSERT命令。不过,通过编写自己的事务脚本文件,也很容易测试其他场景。
下面是 pgbench 的典型输出:
transaction type: TPC-B (sort of) scaling factor: 10 query mode: simple number of clients: 10 number of threads: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 tps = 85.184871 (including connections establishing) tps = 85.296346 (excluding connections establishing)
前六行报告了一些最重要的参数设置。下一行报告已完成的事务数和预期的事务数(后者就是客户端数与每个客户端的事务数的乘积);除非运行在完成前失败,否则这两个数应该相等。(在 -T 模式下,只打印实际的事务数。)最后两行报告每秒事务数,分别计入和不计入启动数据库会话的时间。
默认的类 TPC-B 事务测试要求预先建立特定的表。应使用 -i(初始化)选项调用 pgbench 来创建并填充这些表。(测试 自定义脚本时不需要这一步,但需要自行完成测试所需的准备工作。) 初始化命令如下:
pgbench -i [other-options]dbname
其中 dbname 是要在其中进行测试的已创建 数据库的名称。(可能还需要 -h、 -p 和/或 -U 选项来指定如何连接数据库服务器。)
pgbench -i会创建四个表pgbench_accounts、 pgbench_branches、pgbench_history和pgbench_tellers,并销毁任何已存在的同名表。如果数据库中已经存在这些名称的表,请务必改用其他数据库!
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
你可以(而且对于大多数用途来说,也许应该)使用 -s(缩放因子)选项增加行数。此时还可以使用 -F(填充因子)选项。
完成必要的设置之后,就可以用不带 -i 的命令运行基准测试,即
pgbench [options]dbname
几乎在所有情况下,都需要一些选项才能做出有意义的测试。最重要 的选项是 -c(客户端数量)、 -t(事务数量)、 -T(时间限制)和 -f(指定自定义脚本文件)。 完整列表见下文。
第 F.26.2 节 给出数据库初始化期间使用的 选项,第 F.26.3 节 给出运行基准测试期间 使用的选项,而 第 F.26.4 节 给出两种情况下都有用的 选项。
pgbench 接受以下命令行初始化参数:
-i进入初始化模式所必需。
-F fillfactor以给定的 fillfactor 创建pgbench_accounts、 pgbench_tellers和 pgbench_branches表。 默认值为 100。
-s scale_factor将生成的行数乘以缩放因子。例如, -s 100 会在 pgbench_accounts 表中创建 10,000,000 行。默认值为 1。
pgbench 接受以下命令行基准测试参数:
-c clients模拟的客户端数量,也就是并发数据库会话的数量。默认值为 1。
-C为每个事务建立一个新的连接,而不是每个客户端会话只建立一次。 这有助于测量连接开销。
-d打印调试输出。
-D varname=value为自定义脚本定义一个变量(见下文)。允许使用多个 -D 选项。
-f filename从 filename 读取事务脚本。详见下文。 -N、-S 和 -f 互斥。
-j threadspgbench 内的工作线程数。在多 CPU 机器上使用多个线程会有帮助。客户端数必须时线程数的 整数倍,因为每个线程都会分到相同数量的客户端会话来管理。 默认值为 1。
-l将每个事务所耗时间写入日志文件。详见下文。
-M querymode用于向服务器提交查询的协议:
simple:使用简单查询协议。
extended:使用扩展查询协议。
prepared:使用带预备语句的扩展查询协议。
The default is simple query protocol. (See 第 46 章 for more information.)
-n运行测试前不执行清理。如果你运行的自定义测试场景不包含 标准表 pgbench_accounts、 pgbench_branches、 pgbench_history 和 pgbench_tellers,则此选项是 必需的。
-N不更新 pgbench_tellers 和 pgbench_branches。这会避免在这些表上 发生更新争用,但也会让该测试场景更不像 TPC-B。
-r在基准测试完成后,报告每条命令的平均语句延迟(从客户端视角看到的执行时间)。详情见下文。
-s scale_factor在 pgbench 的输出中报告指定的缩放 因子。对于内置测试,这不是必需的;正确的缩放因子会通过统计 pgbench_branches 表中的行数检测出来。 但是,在测试自定义基准( -f 选项)时,除非使用此选项,否则缩放因子 将报告为 1。
-S执行只读 SELECT 事务,而不是类 TPC-B 测试。
-t transactions每个客户端运行的事务数。默认值为 10。
-T seconds让测试运行这么多秒,而不是每个客户端固定数量的事务。 -t 和 -T 互斥。
-v运行测试前清理全部四个标准表。若既不指定 -n 也不指定 -v,pgbench 将清理 pgbench_tellers 和 pgbench_branches 表,并截断 pgbench_history。
pgbench 接受以下通用命令行参数:
-h hostname数据库服务器的主机名。
-p port数据库服务器的端口号。
-U login用于连接的用户名
默认的事务脚本在每个事务中发出七条命令:
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;
如果指定-N,事务中将不包含第 4 步和第 5 步。如果指定-S,则只执行SELECT。
pgbench 支持运行自定义基准场景,方法 是用从文件读取的事务脚本( -f 选项)替换(前文所述的)默认事务脚本。 在这种情况下,一次“事务”算作脚本文件的一次执行。 甚至可以指定多个脚本(多个 -f 选项),此时每次客户端会话开始新事务时, 都会随机选择其中一个脚本。
脚本文件的格式是每行一条 SQL 命令;不支持跨多行的 SQL 命令。空行以及以--开头的行会被忽略。脚本文件的行还可以是“元命令”,它们由pgbench自身解释,详见下文。
脚本文件有一个简单的变量替换设施。变量可以通过命令行 -D 选项(前文已说明)或下文说明的元命令来 设置。除了由 -D 命令行选项预设的变量之外,变量 scale 会被预设为当前缩放因子。变量一经设置, 就可以通过写成 :variablename 把它的值 插入 SQL 命令中。运行多个客户端会话时,每个会话都有自己的一组 变量。
脚本文件中的元命令以反斜线(\)开头。元命令的参数以空白分隔。支持的元命令如下:
\set varname operand1 [ operator operand2 ]将变量varname设置为一个计算出的整数值。每个operand要么是一个整数常量,要么是一个对具有整数值的变量的:variablename引用。operator可以是+、-、*或/。
示例:
\set ntellers 10 * :scale
\setrandom varname min max将变量varname设置为介于min和max之间(含边界)的一个随机整数值。每个界限既可以是整数常量,也可以是指向某个整数值变量的:variablename引用。
示例:
\setrandom aid 1 :naccounts
\sleep number [ us | ms | s ]让脚本执行休眠指定时长,单位可以是微秒(us)、毫秒(ms)或秒(s)。如果省略单位,则默认为秒。number可以是整数常量,也可以是引用了整数值变量的:variablename。
示例:
\sleep 10 ms
\setshell varname command [ argument ... ]将变量varname设置为 shell 命令command的结果。该命令必须通过标准输出返回一个整数值。
argument可以是文本常量,也可以是指向任意类型变量的:variablename引用。如果要使用以冒号开头的argument,需要在argument开头再添加一个冒号。
示例:
\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
\shell command [ argument ... ]与\setshell相同,但结果会被忽略。
示例:
\shell command literal_argument :variable ::literal_starting_with_colon
作为一个示例,内置的类 TPC-B 事务的全部定义是:
\set nbranches :scale \set ntellers 10 * :scale \set naccounts 100000 * :scale \setrandom aid 1 :naccounts \setrandom bid 1 :nbranches \setrandom tid 1 :ntellers \setrandom delta -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 选项时,pgbench 会把每个事务所耗时间写入日志文件。日志文件名为 pgbench_log., 其中 nnnnnn 是 pgbench 进程的 PID。如果 -j 选项为 2 或更高(创建多个工作线程), 每个线程都会有自己的日志文件。第一个工作线程的日志文件名与 标准单工作线程情形相同。其余工作线程的额外日志文件名为 pgbench_log., 其中 nnn.mmmmmm 是从 1 开始的各工作线程顺序编号。
日志格式如下:
client_idtransaction_notimefile_notime_epochtime_us
其中,time 是事务经过的总时间,单位为微秒, file_no 标识使用的脚本文件(在通过 -f 指定多个脚本时很有用),而 time_epoch/time_us 分别是 Unix 纪元格式的时间戳和以微秒计的偏移量(适合用来生成带小数秒的 ISO 8601 时间戳),表示事务完成的时间。
示例输出如下:
0 199 2241 0 1175850568 995598 0 200 2465 0 1175850568 998079 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663
使用-r选项时,pgbench会收集每个客户端执行的每条语句所经过的事务时间。基准测试完成后,它会报告这些值的平均值,称为每条语句的延迟。
对于默认脚本,输出与下面类似:
starting vacuum...end.
transaction type: TPC-B (sort of)
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
tps = 618.764555 (including connections establishing)
tps = 622.977698 (excluding connections establishing)
statement latencies in milliseconds:
0.004386 \set nbranches 1 * :scale
0.001343 \set ntellers 10 * :scale
0.001212 \set naccounts 100000 * :scale
0.001310 \setrandom aid 1 :naccounts
0.001073 \setrandom bid 1 :nbranches
0.001005 \setrandom tid 1 :ntellers
0.001078 \setrandom delta -5000 5000
0.326152 BEGIN;
0.603376 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
0.454643 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
5.528491 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
7.335435 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
0.371851 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
1.212976 END;
如果指定了多个脚本文件,则会分别为每个脚本文件报告平均值。
注意,为逐语句延迟计算收集额外的计时信息会带来一定开销。这会拖慢平均执行速度,并降低计算出的 TPS。减速幅度在很大程度上取决于平台和硬件。比较启用和未启用延迟报告时的平均 TPS 值,是判断这一计时开销是否显著的好方法。
很容易用pgbench得出完全没有意义的数字。下面给出一些有助于获得有用结果的准则。
首先,绝不要相信任何只运行几秒钟的测试。 使用 -t 或 -T 选项让运行至少持续几分钟,以平均掉噪声。 在某些情况下,可能需要数小时才能获得可重现的数字。最好把 测试多运行几次,看看你的数字是否可重现。
对于默认的类 TPC-B 测试场景,初始化缩放因子 (-s)至少应与你打算测试的最大客户端数 (-c)一样大;否则你测到的将主要是更新争用。 pgbench_branches 表中只有 -s 行,而每个事务都要更新其中一行,因此 -c 值超过 -s 无疑会导致大量事务阻塞等待其他事务。
默认测试场景还会对表初始化后的时间长短非常敏感:表中死元组和无效空间的累积会改变结果。要理解这些结果,必须跟踪更新总数以及何时发生清理。如果启用了自动清理,它可能会给测得的性能带来不可预测的变化。
pgbench的一个局限是:在尝试测试大量客户端会话时,它自己也可能成为瓶颈。可以通过在与数据库服务器不同的机器上运行pgbench来缓解这一点,不过网络延迟必须足够低。甚至可以在多台客户端机器上同时运行多个pgbench实例,对同一台数据库服务器施压。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。