Pgbench
From PostgreSQL 中文维基, PostgreSQL 中文站, PostgreSQL 中国社区, PostgreSQL Chinese community
[编辑] pgbench
pgbench 是一个简单的给 PostgreSQL 做性能测试的程序。它反复运行同样的 SQL 命令序列,可能是在多个并发数据库会话上头,然后检查平均的事务速度(每秒的事务数 tps)。缺省的时候,pgbench 测试一个(松散的)接近 TPC-B 的情况,每个事务包括五个 SELECT,UPDATE,和 INSERT命令。不过,我们可以很轻松地使用自己的事务脚本文件来实现其它情况。
典型的输出看上去会是这样:
transaction type: TPC-B (sort of) scaling factor: 10 number of clients: 10 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)
头四航只是报告一些最重要的参数设置。跟着的一行报告完成的事务数和期望完成的事务数(后者只是客户端数乘以事务数);这两个会相等,除非在完成之前运行就失败了。最后两行报告 TPS 速率,分别有计算启动数据库会话时间和不计算启动会话时间的。
[编辑] 概述
缺省的 TPC-B 类的事务测试需要事先设定特定的表。要使用 pgbench 的 -i (初始化)选项来创建和填充这些表。(如果你测试的是客户自己的脚本,那就不需要这一步,但是你需要自己设置所需的环境)。初始化看上去像:
pgbench -i [ other-options ] dbname
这里的 dbname 是一个已经创建的准备用来测试的数据库名称。(你可能还需要 -h,-p,和/或 -U 选项来声明如何连接到数据库服务器。)
注意:pgbench -i 创建四个表:accounts,branches,history 和 tellers,删除任何现有同名的表。如果你的数据库里有同名的表,要非常非常的小心!
缺省的“缩放因子(scale factor)”为 1 的时候,表初始化的行数为:
table # of rows ------------------------- branches 1 tellers 10 accounts 100000 history 0
你可以(而且,在大多数情况下,可能会)增加表中数据行的方法是使用 -s (缩放因子)选项。-F (填充因子 fillfactor)选项在这个时候也可以用。
一旦你完成了必要的步骤,就可以用不包括 -i 选项的命令来执行性能测试,也就是
pgbench [ options ] dbname
几乎在所有场合下,你都需要一些选项来做有效的测试。最重要的选项是 -c(客户端数目),-t(事务的数目),和 -f (声明一个客户的脚本文件)。参阅下表获取完整的列表。
表 F-14 显示了在数据库初始化过程中使用的选项,表 F-15 显示了运行性能套件的时候的选项,表 F-16 显示了可用于两种场合的选项:
| 选项 | 描述 |
| -i | 要求调用初始化模式。 |
| -s scale_factor | 生成的数据行放大 scale_factor 指定的倍数。比如 -s 100 讲隐含着账号表里有 10,000,000 行。缺省是 1。 |
| -F fillfactor | 用给出的 fillfactor 创建 accounts, tellers 和 branches 表缺省是 100。 |
| 选项 | 描述 |
| -c clients | 模拟的客户数,也就是并发数据库会话数目。缺省是 1。 |
| -t transactions | 每个客户端跑的事务数目。缺省是 10。 |
| -N | 不要更新 tellers 和 branches。这样会避免在这些表上的更新竞争,但是让测试案例更不像 TPC-B 了。 |
| -S | 执行纯 SELECT 的事务,而不是类 TPC-B 的测试。 |
| -f filename | 从 filename 中读取事务脚本。参阅下文获取细节。-N,-S,和 -f 是相互排斥的。 |
| -n | 在运行测试之前不执行 vacuum。如果你跑的是客户化的测试,不包括标准的 accounts,branches,history 和 tellers 表,那么这个选项就是必须的。 |
| -v | 在运行测试之前清理(vacuum)所有四个标准的表。如果不带 -n 也不带 -v,那么 pgbench 将清理 tellers 和 branches 表,并将删除 history 中的所有记录。 |
| -D varname=value | 定义一个客户端脚本使用的变量(见下文)。允许多个 -D 选项。 |
| -C | 为每个事务建立一个新连接,而不是每个客户端线程一个事务。这个有助于测量连接过荷。 |
| -l | 把每个事务花的时间写到 logfile。参阅下文获取细节。 |
| -s scale_factor | 在 pgbench 的输出汇报特定的缩放因子。对于内置的测试来说,这个是没必要的;正确的缩放因子可以通过计算 branches 表的行数得出。不过,在测试客户性能的时候(-f 选项),缩放因子就会报告为 1,除非使用了这个选项。 |
| -d | 打印调试输出。 |
| 选项 | 描述 |
| -h hostname | 数据库服务器的主机 |
| -p port | 数据库服务器的端口 |
| -U login | 连接的用户名 |
[编辑] pgbench 里实际执行的“事务”是什么?
缺省的事务脚本每个事务发出七个命令:
- BEGIN;
- UPDATE accounts SET abalance = abalance + :delta WHERE aid = :aid;
- SELECT abalance FROM accounts WHERE aid = :aid;
- UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
- UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid;
- INSERT INTO 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 为一个计算出的整数值。每个操作数要么是一个整数常量,要么是一个具有整数值的 :variablename 引用。操作符可以是 +,-,*,或者 /。
- 例子:
\set ntellers 10 * :scale
\setrandom varname min max
- 设置变量 varname 为一个范围是从 min 到 max 之间的随机整数值。每个限制可以是一个整数,也可以是一个具有整数值的 :variablename 引用。
- 例子:
\setrandom aid 1 :naccounts
\sleep number [ us | ms | s ]
- 令脚本执行睡眠指定的微秒(us),毫秒(ms)或秒(s)数。如果省略单位,则缺省是秒。数字可以是一个整数常量,也可以是一个具有整数值的 :variablename 引用。
- 例子:
\sleep 10 ms
比如,内置的 TCP-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 accounts SET abalance = abalance + :delta WHERE aid = :aid; SELECT abalance FROM accounts WHERE aid = :aid; UPDATE tellers SET tbalance = tbalance + :delta WHERE tid = :tid; UPDATE branches SET bbalance = bbalance + :delta WHERE bid = :bid; INSERT INTO history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); END;
这个脚本允许事务的每次循环都引用不同的,随机选取的行。(这个例子还说明了为啥每个子会话需要拥有自己的变量 -- 否则它们就不会各自修改不同的行。)
[编辑] 每事务的日志
如果使用了 -l 选项,pgbench 把每个事务花的时间写到 logfile 里。日志文件的名称会是:pgbench_log.nnn,这里的 nnn 是 pgbench 进程的 PID。日志的格式是:
client_id transaction_no time file_no time_epoch time_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
[编辑] 好习惯
我们很容易用 pgbench 产生完全没意义的数字。下面是一些帮助你获取有用结果的原则。
首先,绝对不要相信只跑了几秒钟的测试。把 -t 设置增大到让运行足以跑上几分钟的水平,这样就可以把噪声给平均掉了。有时候你需要跑上几个小时才能获取可复现的数字。最好是让测试跑上几分钟,看看你的数值是否可复现。
对于缺省的 TPC-B 类的测试场景,初始的缩放因子(-s)应该至少和你试图运行的客户端数目(-c)一样大;否则你就实际上是在测量更新竞争。在 branches 表里只有 -s 行,而每个事务都想更新它们之一,所以大于 -s 的 -c 数值将无疑是有大量事务阻塞在等待其它事务上头。
缺省的测试场景也跟表自初始化以来它已经存在的时间有关:在表中积累的死去的行和无用的空间也会改变结果。要理解这些结果,你必须跟踪更新的总数以及何时发生清理。如果打开了 autovacuum,那么可能会看到测量出来的性能有不可预期的变化。
pgbench 的一个限制是在测试大量客户端会话的时候,它自己可能会成为瓶颈。这个问题可以通过在不同的数据库服务器上运行 pgbench 来缓解。或者是在不同的客户机器上并发地运行好几个 pgbench 来测试同一个数据库服务器。
