测试 PostgreSQL 和 MySQL 通常围绕功能正确性、性能、稳定性和安全性展开。以下是核心的测试方法、常用工具和关键步骤。
一、连接与基础功能测试
这是最基本的测试,确保应用能正常连接和操作数据库。
-
使用命令行客户端或GUI工具连接
-
PostgreSQL : 使用
psql命令行或 pgAdmin、DBeaver 等工具。bashpsql -h 主机名 -p 端口 -U 用户名 -d 数据库名 -
MySQL : 使用
mysql命令行或 MySQL Workbench、Navicat 等工具。bashmysql -h 主机名 -P 端口 -u 用户名 -p 数据库名
-
-
执行基本CRUD操作
- 创建表、插入数据、查询、更新、删除,验证SQL语法兼容性和执行结果是否符合预期。
- 测试事务(BEGIN, COMMIT, ROLLBACK)是否正常工作。
二、性能测试(压测)
这是评估数据库处理能力的关键,尤其与您之前设置的连接池参数直接相关。
-
常用压测工具
数据库 推荐工具 主要用途 PostgreSQL pgbench(内置)标准的TPC-B-like基准测试,测试综合事务处理能力。 MySQL sysbench支持CPU、内存、文件I/O、数据库OLTP等多种测试。 两者均可 HammerDB (图形化) 支持TPC-C, TPC-H等更复杂的商业负载测试。 两者均可 自定义脚本 (如用Go/Python编写) 模拟最真实的业务查询逻辑进行压测。 -
关键性能指标
- 吞吐量:QPS(每秒查询数)、TPS(每秒事务数)。
- 延迟:平均响应时间、P95/P99分位响应时间。
- 资源利用率:数据库服务器的CPU、内存、磁盘I/O、网络I/O使用率。
- 连接与错误:当前连接数、连接错误数、慢查询数量。
-
一个简单的压测示例
-
PostgreSQL (使用 pgbench) :
bash# 1. 初始化测试数据(例如,在"test_db"中创建4张表,缩放因子为100) pgbench -h localhost -U postgres -i -s 100 test_db # 2. 运行压测:10个客户端,并发运行60秒 pgbench -h localhost -U postgres -c 10 -j 2 -T 60 test_db -
MySQL (使用 sysbench) :
bash# 1. 准备数据(例如,创建10张表,每张表10万行) sysbench oltp_read_write --db-driver=mysql --mysql-host=localhost \ --mysql-user=root --mysql-password=your_password --mysql-db=sbtest \ --table-size=100000 --tables=10 prepare # 2. 运行压测:8个线程,运行300秒 sysbench oltp_read_write --db-driver=mysql --mysql-host=localhost \ --mysql-user=root --mysql-password=your_password --mysql-db=sbtest \ --threads=8 --time=300 run
-
三、稳定性与可靠性测试
- 长时间压力测试:使用上述压测工具,以稳定的压力运行数小时甚至数天,观察性能曲线是否平稳,内存是否有泄漏。
- 故障恢复测试 :
- 网络闪断:模拟网络中断后,连接池是否能正确重连。
- 数据库重启:重启数据库服务,验证应用是否能自动恢复连接并继续工作。
- 主从切换(如果使用了复制):模拟主库故障,验证备库能否顺利提升为主库,应用能否切换到新主库。
四、安全性测试
- 权限测试:使用不同权限的账户登录,验证其是否只能执行被授权的操作。
- SQL注入测试:使用工具(如 sqlmap)或手动构造异常输入,测试应用层是否有效防范了SQL注入。
- 网络与加密:测试是否强制使用了SSL/TLS加密连接。
五、监控与日志分析
在测试过程中和上线后,持续监控至关重要。
- PostgreSQL : 监控
pg_stat_activity(当前活动)、pg_stat_statements(SQL统计),分析日志中的错误和慢查询。 - MySQL : 监控
SHOW PROCESSLIST(当前连接)、performance_schema和sys库,分析慢查询日志 (slow_query_log) 和错误日志。
总结与建议
- 明确测试目标:是验证功能、寻找性能瓶颈,还是测试高可用方案?
- 模拟真实负载 :尽可能使用贴近业务的SQL进行测试,
pgbench和sysbench的默认模板只是一个起点。 - 从测试环境开始 :切勿在生产数据库上直接进行压测。先在配置相似的测试环境进行。
- 循序渐进:从小并发开始,逐步增加压力,观察各项指标的变化趋势,找到性能拐点。
- 结合应用测试:最真实的测试是使用您的应用程序,配合APM工具进行全链路压测。
通过以上方法的组合,您可以全面评估PostgreSQL或MySQL数据库的健壮性和性能表现,并为优化配置(如您之前关心的最大连接数)提供数据支持。
pgbench 运行结果解读
运行 pgbench -h localhost -U postgres -i -s 100 test_db 的输出解读如下:
输出示例与解读
bash
/ # pgbench -h localhost -U postgres -i -s 100 my_test
dropping old tables...
NOTICE: table "pgbench_accounts" does not exist, skipping
NOTICE: table "pgbench_branches" does not exist, skipping
NOTICE: table "pgbench_history" does not exist, skipping
NOTICE: table "pgbench_tellers" does not exist, skipping
creating tables...
generating data...
100000 of 10000000 tuples (1%) done (elapsed 0.21 s, remaining 20.67 s)
200000 of 10000000 tuples (2%) done (elapsed 0.43 s, remaining 20.88 s)
300000 of 10000000 tuples (3%) done (elapsed 0.67 s, remaining 21.53 s)
400000 of 10000000 tuples (4%) done (elapsed 1.04 s, remaining 24.99 s)
500000 of 10000000 tuples (5%) done (elapsed 4.92 s, remaining 93.43 s)
600000 of 10000000 tuples (6%) done (elapsed 6.87 s, remaining 107.68 s)
700000 of 10000000 tuples (7%) done (elapsed 8.55 s, remaining 113.62 s)
800000 of 10000000 tuples (8%) done (elapsed 10.40 s, remaining 119.58 s)
900000 of 10000000 tuples (9%) done (elapsed 13.97 s, remaining 141.29 s)
1000000 of 10000000 tuples (10%) done (elapsed 15.77 s, remaining 141.93 s)
1100000 of 10000000 tuples (11%) done (elapsed 17.34 s, remaining 140.31 s)
1200000 of 10000000 tuples (12%) done (elapsed 20.19 s, remaining 148.03 s)
1300000 of 10000000 tuples (13%) done (elapsed 22.17 s, remaining 148.38 s)
1400000 of 10000000 tuples (14%) done (elapsed 24.76 s, remaining 152.07 s)
1500000 of 10000000 tuples (15%) done (elapsed 26.15 s, remaining 148.18 s)
1600000 of 10000000 tuples (16%) done (elapsed 27.70 s, remaining 145.42 s)
1700000 of 10000000 tuples (17%) done (elapsed 29.13 s, remaining 142.21 s)
1800000 of 10000000 tuples (18%) done (elapsed 31.50 s, remaining 143.50 s)
1900000 of 10000000 tuples (19%) done (elapsed 32.83 s, remaining 139.96 s)
2000000 of 10000000 tuples (20%) done (elapsed 34.88 s, remaining 139.53 s)
2100000 of 10000000 tuples (21%) done (elapsed 36.45 s, remaining 137.10 s)
2200000 of 10000000 tuples (22%) done (elapsed 39.91 s, remaining 141.50 s)
2300000 of 10000000 tuples (23%) done (elapsed 41.97 s, remaining 140.52 s)
2400000 of 10000000 tuples (24%) done (elapsed 44.01 s, remaining 139.35 s)
2500000 of 10000000 tuples (25%) done (elapsed 45.55 s, remaining 136.65 s)
2600000 of 10000000 tuples (26%) done (elapsed 48.12 s, remaining 136.95 s)
2700000 of 10000000 tuples (27%) done (elapsed 49.53 s, remaining 133.92 s)
2800000 of 10000000 tuples (28%) done (elapsed 51.24 s, remaining 131.77 s)
2900000 of 10000000 tuples (29%) done (elapsed 53.99 s, remaining 132.19 s)
3000000 of 10000000 tuples (30%) done (elapsed 58.19 s, remaining 135.77 s)
3100000 of 10000000 tuples (31%) done (elapsed 60.58 s, remaining 134.83 s)
3200000 of 10000000 tuples (32%) done (elapsed 67.08 s, remaining 142.54 s)
3300000 of 10000000 tuples (33%) done (elapsed 70.47 s, remaining 143.07 s)
3400000 of 10000000 tuples (34%) done (elapsed 75.49 s, remaining 146.54 s)
3500000 of 10000000 tuples (35%) done (elapsed 77.43 s, remaining 143.79 s)
3600000 of 10000000 tuples (36%) done (elapsed 80.40 s, remaining 142.93 s)
3700000 of 10000000 tuples (37%) done (elapsed 82.06 s, remaining 139.72 s)
3800000 of 10000000 tuples (38%) done (elapsed 83.43 s, remaining 136.13 s)
3900000 of 10000000 tuples (39%) done (elapsed 85.26 s, remaining 133.36 s)
4000000 of 10000000 tuples (40%) done (elapsed 88.07 s, remaining 132.11 s)
4100000 of 10000000 tuples (41%) done (elapsed 92.13 s, remaining 132.58 s)
4200000 of 10000000 tuples (42%) done (elapsed 95.45 s, remaining 131.81 s)
4300000 of 10000000 tuples (43%) done (elapsed 99.59 s, remaining 132.01 s)
4400000 of 10000000 tuples (44%) done (elapsed 105.94 s, remaining 134.83 s)
4500000 of 10000000 tuples (45%) done (elapsed 109.89 s, remaining 134.30 s)
4600000 of 10000000 tuples (46%) done (elapsed 111.46 s, remaining 130.84 s)
4700000 of 10000000 tuples (47%) done (elapsed 113.35 s, remaining 127.83 s)
4800000 of 10000000 tuples (48%) done (elapsed 116.31 s, remaining 126.01 s)
4900000 of 10000000 tuples (49%) done (elapsed 118.10 s, remaining 122.92 s)
5000000 of 10000000 tuples (50%) done (elapsed 119.98 s, remaining 119.98 s)
5100000 of 10000000 tuples (51%) done (elapsed 121.57 s, remaining 116.81 s)
5200000 of 10000000 tuples (52%) done (elapsed 123.40 s, remaining 113.91 s)
5300000 of 10000000 tuples (53%) done (elapsed 126.36 s, remaining 112.06 s)
5400000 of 10000000 tuples (54%) done (elapsed 128.37 s, remaining 109.36 s)
5500000 of 10000000 tuples (55%) done (elapsed 130.19 s, remaining 106.52 s)
5600000 of 10000000 tuples (56%) done (elapsed 131.80 s, remaining 103.56 s)
5700000 of 10000000 tuples (57%) done (elapsed 134.26 s, remaining 101.28 s)
5800000 of 10000000 tuples (58%) done (elapsed 135.48 s, remaining 98.11 s)
5900000 of 10000000 tuples (59%) done (elapsed 136.87 s, remaining 95.11 s)
6000000 of 10000000 tuples (60%) done (elapsed 138.48 s, remaining 92.32 s)
6100000 of 10000000 tuples (61%) done (elapsed 141.00 s, remaining 90.15 s)
6200000 of 10000000 tuples (62%) done (elapsed 142.41 s, remaining 87.28 s)
6300000 of 10000000 tuples (63%) done (elapsed 143.84 s, remaining 84.48 s)
6400000 of 10000000 tuples (64%) done (elapsed 145.39 s, remaining 81.78 s)
6500000 of 10000000 tuples (65%) done (elapsed 147.85 s, remaining 79.61 s)
6600000 of 10000000 tuples (66%) done (elapsed 149.26 s, remaining 76.89 s)
6700000 of 10000000 tuples (67%) done (elapsed 150.64 s, remaining 74.20 s)
6800000 of 10000000 tuples (68%) done (elapsed 152.30 s, remaining 71.67 s)
6900000 of 10000000 tuples (69%) done (elapsed 154.69 s, remaining 69.50 s)
7000000 of 10000000 tuples (70%) done (elapsed 155.95 s, remaining 66.84 s)
7100000 of 10000000 tuples (71%) done (elapsed 157.36 s, remaining 64.27 s)
7200000 of 10000000 tuples (72%) done (elapsed 158.85 s, remaining 61.77 s)
7300000 of 10000000 tuples (73%) done (elapsed 161.28 s, remaining 59.65 s)
7400000 of 10000000 tuples (74%) done (elapsed 162.61 s, remaining 57.13 s)
7500000 of 10000000 tuples (75%) done (elapsed 163.96 s, remaining 54.65 s)
7600000 of 10000000 tuples (76%) done (elapsed 165.58 s, remaining 52.29 s)
7700000 of 10000000 tuples (77%) done (elapsed 168.00 s, remaining 50.18 s)
7800000 of 10000000 tuples (78%) done (elapsed 169.42 s, remaining 47.79 s)
7900000 of 10000000 tuples (79%) done (elapsed 170.83 s, remaining 45.41 s)
8000000 of 10000000 tuples (80%) done (elapsed 172.34 s, remaining 43.09 s)
8100000 of 10000000 tuples (81%) done (elapsed 174.75 s, remaining 40.99 s)
8200000 of 10000000 tuples (82%) done (elapsed 176.11 s, remaining 38.66 s)
8300000 of 10000000 tuples (83%) done (elapsed 177.46 s, remaining 36.35 s)
8400000 of 10000000 tuples (84%) done (elapsed 179.02 s, remaining 34.10 s)
8500000 of 10000000 tuples (85%) done (elapsed 180.33 s, remaining 31.82 s)
8600000 of 10000000 tuples (86%) done (elapsed 182.78 s, remaining 29.75 s)
8700000 of 10000000 tuples (87%) done (elapsed 184.13 s, remaining 27.51 s)
8800000 of 10000000 tuples (88%) done (elapsed 185.68 s, remaining 25.32 s)
8900000 of 10000000 tuples (89%) done (elapsed 186.91 s, remaining 23.10 s)
9000000 of 10000000 tuples (90%) done (elapsed 189.42 s, remaining 21.05 s)
9100000 of 10000000 tuples (91%) done (elapsed 190.84 s, remaining 18.87 s)
9200000 of 10000000 tuples (92%) done (elapsed 192.48 s, remaining 16.74 s)
9300000 of 10000000 tuples (93%) done (elapsed 193.78 s, remaining 14.59 s)
9400000 of 10000000 tuples (94%) done (elapsed 196.32 s, remaining 12.53 s)
9500000 of 10000000 tuples (95%) done (elapsed 197.77 s, remaining 10.41 s)
9600000 of 10000000 tuples (96%) done (elapsed 199.26 s, remaining 8.30 s)
9700000 of 10000000 tuples (97%) done (elapsed 200.63 s, remaining 6.21 s)
9800000 of 10000000 tuples (98%) done (elapsed 203.02 s, remaining 4.14 s)
9900000 of 10000000 tuples (99%) done (elapsed 204.15 s, remaining 2.06 s)
10000000 of 10000000 tuples (100%) done (elapsed 205.41 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done.
/ # pgbench -h localhost -U postgres -c 10 -j 2 -T 60;
ERROR: relation "pgbench_branches" does not exist
LINE 1: select count(*) from pgbench_branches
^
Perhaps you need to do initialization ("pgbench -i") in database "postgres"
/ # pgbench -h localhost -U postgres -c 10 -j 2 -T 60 my_test;
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 10
number of threads: 2
duration: 60 s
number of transactions actually processed: 77566
latency average = 7.736 ms
tps = 1292.666229 (including connections establishing)
tps = 1293.665486 (excluding connections establishing)
/ # pgbench -h localhost -U postgres -c 30 -j 2 -T 60 my_test;
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 30
number of threads: 2
duration: 60 s
number of transactions actually processed: 102295
latency average = 17.612 ms
tps = 1703.401411 (including connections establishing)
tps = 1704.796423 (excluding connections establishing)
/ # pgbench -h localhost -U postgres -c 1000 -j 2 -T 60 my_test;
starting vacuum...end.
connection to database "my_test" failed:
FATAL: sorry, too many clients already
connection to database "my_test" failed:
FATAL: sorry, too many clients already
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 1000
number of threads: 2
duration: 60 s
number of transactions actually processed: 0
/ # pgbench -h localhost -U postgres -c 100 -j 2 -T 60 my_test;
starting vacuum...end.
connection to database "my_test" failed:
FATAL: sorry, too many clients already
^C
/ # pgbench -h localhost -U postgres -c 90 -j 2 -T 60 my_test;
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 90
number of threads: 2
duration: 60 s
number of transactions actually processed: 64460
latency average = 84.313 ms
tps = 1067.455244 (including connections establishing)
tps = 1068.277856 (excluding connections establishing)
/ #
详细解读
1. 初始化步骤分解
| 输出行 | 含义解析 | 数据量计算 (缩放因子 s=100) |
|---|---|---|
dropping old tables... |
尝试删除可能存在的旧测试表 | - |
4个 NOTICE: table "xxx" does not exist, skipping |
表不存在(正常情况,第一次初始化) | - |
creating tables... |
创建4个标准表结构 | - |
creating 100 branches... |
在 pgbench_branches 表中插入100行 |
branches = s = 100 |
creating 1000 tellers... |
在 pgbench_tellers 表中插入1000行 |
tellers = 10 × s = 1000 |
creating 10000000 accounts in pgbench_accounts... |
在 pgbench_accounts 表中插入1000万行 |
accounts = 100,000 × s = 10,000,000 |
vacuum... |
执行VACUUM操作,清理和优化表 | - |
set primary keys... |
设置主键约束 | - |
done. |
初始化完成 | - |
2. 表结构说明
初始化后创建4个表:
-
pgbench_accounts (最大的表)
- 行数:100,000 × 缩放因子 = 10,000,000 行
- 每行约200字节
- 估算大小:~2 GB
- 主键:aid (account ID)
-
pgbench_branches
- 行数:1 × 缩放因子 = 100 行
- 主键:bid (branch ID)
-
pgbench_tellers
- 行数:10 × 缩放因子 = 1,000 行
- 主键:tid (teller ID)
-
pgbench_history
- 初始化时为0行,在压测运行时会插入数据
- 无主键,只有索引
3. 数据量估算
bash
# 根据缩放因子 s=100 估算
- 总行数 ≈ 100 (branches) + 1,000 (tellers) + 10,000,000 (accounts) = 10,000,100 行
- 磁盘空间 ≈ 2-3 GB(取决于你的PostgreSQL版本和配置)
- 索引大小 ≈ 0.5-1 GB
4. 重要参数说明
-
-s 100:缩放因子 (scale factor)- 核心参数,决定测试数据量大小
- 值越大,数据量越大,测试越接近真实大规模场景
- 常用值:10(小型), 50(中型), 100(中大型), 1000(大型)
-
-i:初始化模式 (initialize)- 只创建表结构和数据,不运行测试
-
-h localhost -U postgres:连接参数- 主机和用户名
-
test_db:目标数据库名
5. 初始化后的验证
初始化完成后,可以验证数据:
sql
-- 连接到 test_db
psql -h localhost -U postgres -d test_db
-- 查看表大小和数据量
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as total_size
FROM pg_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
-- 查看行数统计
SELECT
'pgbench_accounts' as table_name,
(SELECT count(*) FROM pgbench_accounts) as row_count
UNION ALL
SELECT
'pgbench_branches',
(SELECT count(*) FROM pgbench_branches)
UNION ALL
SELECT
'pgbench_tellers',
(SELECT count(*) FROM pgbench_tellers)
UNION ALL
SELECT
'pgbench_history',
(SELECT count(*) FROM pgbench_history);
6. 后续操作建议
初始化完成后,就可以运行实际的性能测试了:
bash
# 运行一个简单的基准测试
pgbench -h localhost -U postgres -c 10 -j 2 -T 60 test_db
# -c 10: 10个客户端并发
# -j 2: 2个工作线程
# -T 60: 运行60秒
7. 常见问题与注意事项
-
时间较长:当缩放因子较大时(如1000以上),初始化可能需要几分钟到几十分钟。
-
磁盘空间:确保有足够的磁盘空间,特别是对于大缩放因子。
-
内存使用:初始化过程会占用一定内存,但通常不会特别高。
-
取消初始化 :如果中途想取消,按
Ctrl+C,但已创建的数据不会被自动清理。 -
重新初始化 :如果想重新开始,需要先手动删除表或使用
-D参数指定清理。
初始化完成后,pgbench创建了一个标准化的测试环境,适合进行数据库性能对比测试和压力测试。
我们收到一个pgbench测试的输出结果,需要解读这个结果。输出如下:
bash
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 10
number of threads: 2
duration: 60 s
number of transactions actually processed: 77566
latency average = 7.736 ms
tps = 1292.666229 (including connections establishing)
tps = 1293.665486 (excluding connections establishing)
输出解读
- 测试配置参数
- transaction type: <builtin: TPC-B (sort of)>
使用内置的TPC-B类似事务,这是pgbench默认的事务脚本,模拟简单的银行交易。 - scaling factor: 100
缩放因子为100,与之前初始化时一致。这意味着测试数据量:branches表100行,tellers表1000行,accounts表1000万行。 - query mode: simple
使用简单查询模式(每个查询单独发送和接收)。另一种是扩展模式(extended,使用预处理语句)。 - number of clients: 10
模拟10个客户端并发执行事务。 - number of threads: 2
pgbench使用2个线程来管理这10个客户端。注意:线程数小于客户端数,所以每个线程要处理多个客户端。 - duration: 60 s
测试持续时间为60秒。
- 测试结果
- number of transactions actually processed: 77566
在60秒内,总共完成了77566个事务(即TPC-B类型的事务)。 - latency average: 7.736 ms
每个事务的平均延迟(响应时间)为7.736毫秒。注意:这是从客户端角度测量的往返时间。 - tps = 1292.666229 (including connections establishing)
包括建立连接时间在内的每秒事务数(TPS)为1292.67。因为pgbench在测试开始时建立连接,然后运行事务,所以这个TPS包括了连接建立的时间(但连接建立通常只在开始时发生,所以对长时间测试影响很小)。 - tps = 1293.665486 (excluding connections establishing)
不包括连接建立时间的TPS为1293.67。与上面的值非常接近,说明连接建立时间对整体TPS影响很小。
- 性能分析
- TPS(每秒事务数):约1293。这是衡量数据库性能的关键指标,表示每秒能处理1293个类似TPC-B的事务。
平均延迟:7.736毫秒。对于每个事务,平均需要7.736毫秒完成。
- 其他注意事项
- 这个测试是在本地主机(localhost)上进行的,所以网络延迟几乎为零。如果在远程服务器上测试,网络延迟会影响结果。
- 测试使用的是简单查询模式,如果使用扩展模式(预处理语句),性能可能会有所不同。
- 测试结果受硬件(CPU、内存、磁盘)、PostgreSQL配置参数以及系统负载的影响。这个结果只能作为参考,实际生产环境需要更全面的测试。
- 如何改进测试
- 可以调整客户端数(-c)和线程数(-j)来寻找最佳并发配置。
- 可以尝试更复杂的自定义事务脚本,以模拟真实业务场景。
- 可以延长测试时间(-T)以获得更稳定的平均值。
- 可以结合数据库监控(如使用pg_stat_statements)分析查询性能。
典型的 pgbench 性能测试结果。以下是详细解读:
核心性能指标解读
1. 关键结果数据
| 指标 | 数值 | 含义与评价 |
|---|---|---|
| 总事务数 | 77,566 | 60秒内完成的事务总数 |
| 平均延迟 | 7.736 ms | 每个事务的平均响应时间 |
| TPS (含连接建立) | 1,292.67 | 包含连接建立时间的每秒事务数 |
| TPS (不含连接建立) | 1,293.67 | 纯事务处理的每秒事务数 |
2. 测试配置参数
- 事务类型 : TPC-B (类银行交易)
- 包含:更新账户余额、更新分行余额、更新柜员余额、插入历史记录
- 缩放因子 : 100
- 对应:100个分行、1,000个柜员、1,000万个账户
- 查询模式: simple (简单协议)
- 客户端数: 10 (并发连接数)
- 线程数: 2 (pgbench工作线程)
- 持续时间: 60秒
性能分析
1. TPS 分析
- 1,293 TPS 是一个中等偏上的性能表现
- 影响因素 :
- 硬件配置(CPU、内存、磁盘类型)
- PostgreSQL 配置参数(shared_buffers、work_mem等)
- 数据量大小(1,000万账户)
- 本地测试(无网络延迟)
2. 延迟分析
- 7.736ms 平均延迟 对于 TPC-B 事务是合理的
- TPC-B 事务包含多个更新和插入操作
- 在机械硬盘上通常为 10-30ms,SSD 上可降至 1-5ms
3. 连接开销分析
TPS (含连接) = 1,292.67
TPS (不含连接) = 1,293.67
差值 = 1.0 TPS (仅 0.08% 差异)
- 连接建立开销极小,说明连接池配置合理
- 测试中连接是预先建立的,不是每个事务新建连接
与预期性能对比
1. 参考基准
| 硬件/配置 | 预期 TPS 范围 | 您的结果 |
|---|---|---|
| 普通机械硬盘 + 默认配置 | 500-1,500 | 1,293 (正常) |
| SSD + 优化配置 | 2,000-5,000+ | - |
| 高端 NVMe + 深度优化 | 10,000+ | - |
2. 性能瓶颈排查方向
如果 TPS 低于预期,可检查:
sql
-- 1. 检查数据库配置
SHOW shared_buffers; -- 推荐为内存的 25%
SHOW work_mem; -- 推荐 4-32MB
SHOW max_connections; -- 连接数限制
SHOW checkpoint_timeout; -- 检查点间隔
-- 2. 监控系统资源
-- 使用 top/htop 查看 CPU 使用率
-- 使用 iostat 查看磁盘 I/O
-- 使用 vmstat 查看内存和交换分区
优化建议
1. 调整 pgbench 参数
bash
# 增加客户端数(测试更高并发)
pgbench -h localhost -U postgres -c 20 -j 4 -T 60 my_test
# 使用 prepared 模式(减少解析开销)
pgbench -h localhost -U postgres -c 10 -j 2 -T 60 -M prepared my_test
# 只读测试(基准对比)
pgbench -h localhost -U postgres -c 10 -j 2 -T 60 -S my_test
2. PostgreSQL 配置优化
ini
# postgresql.conf 关键参数
shared_buffers = 2GB # 根据内存调整(25%)
effective_cache_size = 6GB # 根据内存调整(75%)
work_mem = 16MB # 每个操作的内存
max_connections = 100 # 最大连接数
checkpoint_timeout = 15min # 检查点间隔
3. 进阶测试方案
bash
# 1. 多阶段测试(模拟不同负载)
pgbench -h localhost -U postgres -c 10 -T 30 -M prepared my_test
pgbench -h localhost -U postgres -c 50 -T 30 -M prepared my_test
pgbench -h localhost -U postgres -c 100 -T 30 -M prepared my_test
# 2. 自定义脚本测试
cat custom_script.sql
\set aid random(1, 10000000)
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
pgbench -h localhost -U postgres -c 10 -T 60 -f custom_script.sql my_test
结果可视化建议
1. 创建性能趋势图
bash
# 测试不同并发下的性能
for clients in 1 5 10 20 50 100
do
pgbench -h localhost -U postgres -c $clients -j 2 -T 30 my_test | \
grep "tps = " | tail -1 >> results.txt
done
2. 监控实时指标
bash
# 在另一个终端监控
watch -n 1 "psql -h localhost -U postgres -d my_test -c \
\"SELECT count(*) FROM pgbench_accounts; \
SELECT count(*) FROM pgbench_history;\""
总结评价
您的测试结果 1,293 TPS 表明:
- 数据库运行正常:能稳定处理并发请求
- 配置基本合理:连接池、内存设置等没有明显问题
- 有优化空间:通过调整配置和硬件,TPS 可能提升 2-5 倍
下一步建议:
- 使用
-M prepared模式重新测试 - 逐步增加客户端数(-c 20, 50, 100)找到性能拐点
- 调整 PostgreSQL 配置参数后对比测试
- 如果使用机械硬盘,考虑升级到 SSD
判断 PostgreSQL 性能是否需要优化,主要看以下几个关键指标是否出现异常:
一、性能问题的明确信号
1. TPS 异常低(与硬件不匹配)
| 硬件配置 | 预期 TPS 范围 | 问题信号 |
|---|---|---|
| NVMe SSD + 16GB+ 内存 | < 5,000 TPS | 明显偏低 |
| SATA SSD + 8GB 内存 | < 2,000 TPS | 需要检查 |
| 机械硬盘 + 4GB 内存 | < 500 TPS | 可能有问题 |
| 云服务器基础型 | 低于同规格官方基准 50% | 需要优化 |
2. 延迟异常高
| 延迟范围 | 评价 | 可能问题 |
|---|---|---|
| < 10ms | 优秀 | - |
| 10-50ms | 正常 | - |
| 50-100ms | 偏高 | 配置或硬件瓶颈 |
| > 100ms | 严重问题 | 必须优化 |
3. 资源使用异常
bash
# 监控命令示例
top # CPU使用率 > 70% 持续
iostat -x 1 # await > 20ms, util > 80%
vmstat 1 # si/so > 0 (发生交换)
问题信号:
- CPU 持续 > 80%
- 磁盘 I/O 等待时间 > 50ms
- 内存交换频繁发生
- 连接数接近
max_connections限制
二、具体问题场景与解决方案
场景1:TPS 远低于预期
您的测试结果:1,293 TPS
- 如果这是 NVMe SSD 的结果 → 需要优化
- 如果这是 机械硬盘 的结果 → 基本正常
检查步骤:
sql
-- 1. 检查关键配置
SELECT name, setting, unit FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'max_connections', 'checkpoint_timeout');
-- 2. 检查当前活动连接
SELECT count(*) as total_connections,
count(*) FILTER (WHERE state = 'active') as active_connections
FROM pg_stat_activity;
-- 3. 检查锁等待
SELECT blocked_locks.pid AS blocked_pid,
blocking_locks.pid AS blocking_pid
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
WHERE NOT blocked_locks.granted;
场景2:延迟波动大或持续增长
问题表现:
- 测试开始时延迟 5ms,结束时延迟 50ms
- P95/P99 延迟远高于平均延迟
解决方案:
ini
# postgresql.conf 调整
shared_buffers = 2GB # 增加共享缓冲区
work_mem = 16MB # 增加排序内存
maintenance_work_mem = 256MB # 增加维护操作内存
effective_cache_size = 6GB # 优化器假设的缓存大小
random_page_cost = 1.1 # SSD设置为1.0-1.1
场景3:连接数问题
问题表现:
错误: sorry, too many clients already
解决方案:
sql
-- 1. 增加最大连接数(需重启)
ALTER SYSTEM SET max_connections = 200;
-- 2. 使用连接池(推荐)
-- 使用 pgbouncer 或 pgpool-II
-- 配置连接复用,减少实际数据库连接数
三、性能基准对比表
| 测试场景 | 正常范围 | 警告阈值 | 严重问题 |
|---|---|---|---|
| TPC-B 测试 | |||
| - NVMe SSD | 5,000-15,000 TPS | < 3,000 TPS | < 1,000 TPS |
| - SATA SSD | 2,000-5,000 TPS | < 1,200 TPS | < 500 TPS |
| - 机械硬盘 | 500-2,000 TPS | < 300 TPS | < 100 TPS |
| 延迟 | 5-20ms | 20-50ms | > 50ms |
| CPU使用率 | < 70% | 70-90% | > 90% |
| 磁盘 I/O 等待 | < 10ms | 10-30ms | > 30ms |
四、系统化诊断流程
步骤1:快速健康检查
bash
# 1. 检查数据库大小
psql -h localhost -U postgres -d my_test -c "
SELECT pg_size_pretty(pg_database_size('my_test')) as db_size;"
# 2. 检查表大小和膨胀
SELECT schemaname, tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size,
n_dead_tup as dead_tuples
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
LIMIT 10;
# 3. 检查索引使用情况
SELECT schemaname, tablename, indexname,
idx_scan as index_scans
FROM pg_stat_user_indexes
WHERE idx_scan = 0 -- 从未使用过的索引
ORDER BY schemaname, tablename;
步骤2:压力测试诊断
bash
# 1. 逐步增加并发,观察性能变化
for clients in 1 5 10 20 50 100 200
do
echo "=== 测试并发数: $clients ==="
pgbench -h localhost -U postgres -c $clients -j 2 -T 30 my_test | \
grep -E "tps = |latency average ="
done
# 2. 监控系统资源(另开终端)
watch -n 1 "top -b -n1 | head -20"
步骤3:分析性能瓶颈
sql
-- 1. 查看等待事件
SELECT wait_event_type, wait_event, count(*)
FROM pg_stat_activity
WHERE state = 'active'
GROUP BY 1, 2
ORDER BY 3 DESC;
-- 2. 查看慢查询(需要先开启)
-- 在 postgresql.conf 中设置:
-- shared_preload_libraries = 'pg_stat_statements'
-- pg_stat_statements.track = all
SELECT query, calls, total_time, mean_time,
rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;
五、必须立即优化的场景
- TPS 持续下降:测试期间 TPS 越来越低
- 延迟指数增长:从 10ms 增长到 100ms+
- 错误率 > 1%:大量连接超时或失败
- CPU 持续 100%:且 TPS 很低
- 磁盘 I/O 等待 > 100ms:明显磁盘瓶颈
- 内存交换频繁:si/so 持续 > 0
六、优化优先级
高优先级(立即处理):
- 内存配置错误 :
shared_buffers太小 - 检查点过频 :
checkpoint_timeout太短 - 连接数不足:频繁连接拒绝
- 缺少索引:全表扫描频繁
中优先级(近期优化):
- work_mem 不足:大量磁盘排序
- autovacuum 配置:表膨胀严重
- WAL 配置:写入性能瓶颈
低优先级(长期优化):
- 查询重写:复杂查询优化
- 分区表:大数据量表
- 复制与读写分离:高并发场景
总结判断标准
您的 1,293 TPS 是否需要优化?
-
先看硬件:
- 如果是 机械硬盘:正常,可小优化
- 如果是 SSD:偏低,需要优化
- 如果是 NVMe:明显偏低,必须优化
-
再看趋势:
- 运行 60 秒 TPS 稳定 → 正常
- TPS 持续下降 → 有问题
-
最后看资源:
- CPU < 50%,磁盘 I/O < 20ms → 配置可优化
- CPU > 80%,磁盘 I/O > 50ms → 硬件瓶颈
建议行动:
- 先确认硬件类型
- 运行
top和iostat查看资源使用 - 根据上述诊断流程找出瓶颈
- 针对性调整配置后重新测试
记住:优化前一定要有基准测试数据,优化后对比验证效果。