选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.4 已于 2020 年 2 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

pgbench

pgbench — 运行 PostgreSQL 基准测试

大纲

pgbench -i [option...] [dbname]

pgbench [option...] [dbname]

描述

pgbench是一个用于对PostgreSQL执行基准测试的简单程序。它会反复执行同一组 SQL 命令,也可在多个并发数据库会话中运行,然后计算平均事务速率(每秒事务数)。默认情况下,pgbench测试的是一个大体上基于 TPC-B 的场景,每个事务包含五条SELECTUPDATEINSERT命令。不过,通过编写自己的事务脚本文件,也很容易测试其他场景。

下面是 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_accountspgbench_branchespgbench_historypgbench_tellers,并销毁任何已存在的同名表。如果数据库中已经存在这些名称的表,请务必改用其他数据库!

在默认的比例因子 1 下,这些表最初包含如下行数:

表                      行数
---------------------------------
pgbench_branches        1
pgbench_tellers         10
pgbench_accounts        100000
pgbench_history         0

可以使用-s(比例因子)选项来增加行数,而且在大多数场景下通常也应该这样做。此时还可以配合使用-F(fillfactor)选项。

完成必要的准备后,就可以使用不带-i的命令运行基准测试,也就是:

pgbench [ options ] dbname

几乎在所有情况下,都需要附加一些选项才能得到有意义的测试。最重要的选项是-c(客户端数)、 -t(事务数)、-T(时间限制)以及-f(指定自定义脚本文件)。完整列表见下文。

选项

以下内容分为三个小节:数据库初始化和运行基准测试时使用不同的选项,而有些选项在这两种情况下都适用。

初始化选项

pgbench 接受以下命令行初始化参数:

-i
--initialize

进入初始化模式所必需。

-F fillfactor
--fillfactor=fillfactor

以给定的 fillfactor 创建pgbench_accountspgbench_tellerspgbench_branches表。 默认值为 100。

-n
--no-vacuum

初始化后不执行任何清理。

-q
--quiet

将日志切换为安静模式,每 5 秒只输出一条进度消息。默认日志每 100000 行打印一条消息,因此通常每秒输出很多行(尤其是在性能良好的硬件上)。

-s scale_factor
--scale=scale_factor

将生成的行数乘以比例因子。 例如,-s 100会在pgbench_accounts表中创建 10,000,000 行。 默认值为 1。 当比例达到 20,000 或更大时,用于保存账户标识符的列(aid列) 将切换到使用更大的整数(bigint), 以便容纳账户标识符的取值范围。

--foreign-keys

在标准表之间创建外键约束。

--index-tablespace=index_tablespace

在指定的表空间中创建索引,而不是默认的表空间。

--tablespace=tablespace

在指定的表空间中创建表,而不是默认的表空间。

--unlogged-tables

将所有表创建为不记录 WAL 的表,而不是永久表。

基准测试选项

pgbench 接受以下命令行基准测试参数:

-c clients
--client=clients

模拟的客户端数量,也就是并发数据库会话的数量。默认值为 1。

-C
--connect

为每个事务建立一个新连接,而不是仅在每个客户端会话中执行一次。 这对于测量连接开销很有用。

-d
--debug

打印调试输出。

-D varname=value
--define=varname=value

定义一个变量,供自定义脚本使用(见下文)。 允许使用多个-D选项。

-f filename
--file=filename

filename文件中读取事务脚本。 详情见下文。-N-S-f 互斥。

-j threads
--jobs=threads

pgbench中的工作线程数。 在多 CPU 机器上使用多个线程可能会有所帮助。 客户端数必须能够被线程数整除,因为每个线程会被分配到相同数量的客户端会话来管理。 默认值为 1。

-l
--log

将每个事务所花的时间写入日志文件。 详情见下文。

-M querymode
--protocol=querymode

用于向服务器提交查询的协议:

  • simple:使用简单查询协议。

  • extended:使用扩展查询协议。

  • prepared:使用带有预备语句的扩展查询协议。

默认为简单查询协议。(详见 第 49 章。)

-n
--no-vacuum

在运行测试前不执行任何清理。 如果运行的是不包含标准表pgbench_accountspgbench_branchespgbench_historypgbench_tellers的自定义测试场景,则此选项是必需的

-N
--skip-some-updates

不更新pgbench_tellerspgbench_branches。这会避免在这些表上发生更新争用,但也会让该测试场景更不像 TPC-B。

-P sec
--progress=sec

sec秒显示一次进度报告。报告包括自运行开始以来的时间、自上次报告以来的 TPS,以及自上次报告以来事务延迟的平均值和标准差。使用限流(-R)时,延迟是相对于事务计划开始时间计算的,而不是实际开始时间,因此其中也包含平均计划滞后时间。

-r
--report-latencies

在基准测试完成后,报告每条命令的平均语句延迟(从客户端视角看到的执行时间)。详情见下文。

-R rate
--rate=rate

以指定速率执行事务,而不是像默认行为那样尽可能快地运行。速率以每秒事务数表示。 如果目标速率高于可达到的最大速率,则速率限制不会影响结果。

该速率通过让事务沿着一条符合泊松分布的时间线启动来实现。预期开始时间表是根据客户端首次启动的时间向前推进的,而不是根据前一个事务结束的时间。这意味着,当某些事务超过其原定结束时间时,后续事务仍有可能重新赶上计划。

启用限流后,运行结束时报告的事务延迟是从计划开始时间计算的,因此它包含每个事务等待前一个事务完成的时间。 这段等待时间称为计划滞后时间,其平均值和最大值也会单独报告。若要得到相对于事务实际开始时间的延迟,也就是事务在数据库中实际执行所花费的时间, 可以用报告中的延迟减去计划滞后时间。

较高的计划滞后时间表明,在所选客户端数和线程数下,系统无法以指定速率处理事务。 当平均事务执行时间长于事务之间的计划间隔时,后续事务会不断进一步落后, 而计划滞后时间也会随着测试持续时间增加。在这种情况下,需要降低指定的事务速率。

-s scale_factor
--scale=scale_factor

pgbench输出中报告指定的比例因子。 对于内置测试,这没有必要;系统会通过统计pgbench_branches表中的行数来检测正确的比例因子。 但在只测试自定义基准(-f选项)时, 除非使用此选项,否则比例因子会被报告为 1。

-S
--select-only

执行只含 SELECT 的事务,而不是类 TPC-B 测试。

-t transactions
--transactions=transactions

每个客户端运行的事务数量。默认值为10。

-T seconds
--time=seconds

让测试运行指定的秒数,而不是让每个客户端执行固定数量的事务。-t-T 是互斥的。

-v
--vacuum-all

在运行测试之前,对四个标准表全部执行清理。 如果既不使用-n也不使用-v,pgbench 会对 pgbench_tellerspgbench_branches 表进行清理,并截断pgbench_history

--aggregate-interval=seconds

聚合间隔的长度(以秒为单位)。只能与-l一起使用—— 使用此选项时,日志包含每个间隔的摘要(事务数、最小/最大延迟, 以及两个对方差估计有用的附加字段)。

此选项目前在 Windows 上不受支持。

--sampling-rate=rate

写入日志时使用的采样率,用于减少生成的日志量。如果给定此选项, 则只记录指定比例的事务。1.0 表示记录全部事务,0.05 表示只记录 5% 的事务。

处理日志文件时,记得把采样率考虑进去。例如,计算 TPS 值时,需要按采样率将数字乘以相应倍数(例如采样率为 0.01 时,只能得到实际 TPS 的 1/100)。

公共选项

pgbench 接受以下通用命令行参数:

-h hostname
--host=hostname

数据库服务器的主机名。

-p port
--port=port

数据库服务器的端口号。

-U login
--username=login

连接时使用的用户名。

-V
--version

打印pgbench版本并退出。

-?
--help

显示pgbench命令行参数的帮助信息并退出。

注解

在 pgbench 中实际执行的事务是什么?

默认的事务脚本在每个事务中发出七条命令:

  1. BEGIN;

  2. UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

  3. SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

  4. UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

  5. UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

  6. INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

  7. END;

如果指定-N,事务中将不包含第 4 步和第 5 步。如果指定-S,则只执行SELECT

自定义脚本

pgbench支持自定义基准测试场景:只需用从文件中读取的事务脚本(-f选项)替换默认事务脚本(见上文)即可。在这种情况下,一个事务就表示脚本文件的一次执行。你甚至可以指定多个脚本(多个-f选项),此时每次客户端会话开始新事务时,都会从这些脚本中随机选择一个。

脚本文件的格式是每行一条 SQL 命令;不支持跨多行的 SQL 命令。空行以及以--开头的行会被忽略。脚本文件的行还可以是元命令,它们由pgbench自身解释,详见下文。

脚本文件提供了简单的变量替换功能。变量可以通过前面介绍的命令行-D选项设置,也可以通过下面介绍的元命令设置。除了由-D命令行选项预设的变量外,还有一些自动预设的变量,列于表 G.1中。使用-D为这些变量指定的值优先于自动预设值。设置变量后,就可以通过书写:variablename将变量值插入 SQL 命令。在运行多个客户端会话时,每个会话都有自己的一组变量。

表 G.1. 自动变量

变量 简介
scale 当前比例因子
client_id 标识客户端会话的唯一编号(从零开始)

脚本文件中的元命令以反斜线(\)开头。元命令的参数以空白分隔。支持的元命令如下:

\set varname operand1 [ operator operand2 ]

将变量varname设置为一个计算出的整数值。每个operand要么是一个整数常量,要么是一个对具有整数值的变量的:variablename引用。operator可以是+-*/

示例:

\set ntellers 10 * :scale
\setrandom varname min max

将变量varname设置为介于minmax之间(含边界)的一个随机整数值。每个界限既可以是整数常量,也可以是指向某个整数值变量的: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选项但未使用--aggregate-interval时,pgbench会将每个事务所花的时间写入日志文件。日志文件名为pgbench_log.nnn,其中nnn是 pgbench 进程的 PID。如果-j选项为 2 或更高(从而创建多个工作线程),则每个工作线程都有自己的日志文件。第一个工作线程的日志文件名与标准单工作线程情况相同。其他工作线程的附加日志文件名为pgbench_log.nnn.mmm,其中mmm是每个工作线程从 1 开始的顺序编号。

日志格式如下:

client_id transaction_no time file_no time_epoch time_us [schedule_lag]

其中,time 是事务经过的总时间,单位为微秒, file_no 标识使用的脚本文件(在通过 -f 指定多个脚本时很有用),而 time_epoch/time_us 分别是 Unix 纪元格式的时间戳和以微秒计的偏移量(适合用来生成带小数秒的 ISO 8601 时间戳),表示事务完成的时间。 schedule_lag 字段是事务计划开始时间与实际开始时间之间的差值,单位为微秒。它仅在使用 --rate 选项时出现。

示例输出如下:

 0 199 2241 0 1175850568 995598
 0 200 2465 0 1175850568 998079
 0 201 2513 0 1175850569 608
 0 202 2038 0 1175850569 2663

在能够处理大量事务的硬件上运行长时间测试时,日志文件可能会变得非常大。可以使用--sampling-rate选项,仅记录事务的随机样本。

聚合日志记录

使用 --aggregate-interval 选项时,日志使用的格式略有不同:

interval_start num_of_transactions latency_sum latency_2_sum min_latency max_latency [lag_sum lag_2_sum min_lag max_lag]

其中,interval_start 是时间区间的开始时间(Unix 纪元格式时间戳), num_of_transactions 是区间内的事务数, latency_sum 是延迟的总和(这样你可以方便地计算平均延迟)。 接下来的两个字段可用于方差估计——latency_sum 是延迟的总和, 而latency_2_sum 是延迟的平方和。再接下来的两个字段是 min_latency(区间内的最小延迟)和 max_latency(区间内的最大延迟)。事务在提交时计入其所在的时间区间。 最后四个字段lag_sumlag_2_summin_lagmax_lag仅在使用--rate选项时出现。 它们根据各事务等待前一事务完成的时间计算,即各事务计划开始时间与实际开始时间之间的差值。

下面是输出示例:

1345828501 5601 1542744 483552416 61 2573
1345828503 7884 1979812 565806736 60 1479
1345828505 7208 1979422 567277552 59 1391
1345828507 7685 1980268 569784714 60 1398
1345828509 7073 1979779 573489941 236 1411

请注意,普通(未聚合)日志文件包含对自定义脚本文件的引用,而聚合日志不包含。因此,如果需要按脚本区分的数据,就必须自行聚合。

逐语句延迟

使用-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实例,对同一台数据库服务器施压。

安全性

如果不受信任的用户能够访问尚未采用模式的安全使用方式的数据库,就不要在该数据库中运行pgbenchpgbench使用非限定名称,并且不会更改搜索路径。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。