【MySQL深入详解】第07篇:基准测试方法论——如何科学评估MySQL性能

3 阅读6分钟

开篇引入

"这个服务器能扛多少QPS?" "我们打算上8.0版本,性能会提升还是下降?" "换了SSD后,性能能提升多少?"

面对这些问题,你能给出一个准确的答案吗?如果不能,说明你需要一个基准测试

基准测试不是"跑个SQL看看多快"那么简单。一套科学的基准测试能帮你:

  • 在上线前发现性能瓶颈
  • 量化系统容量
  • 对比不同配置的差异
  • 验证优化效果

《高性能MySQL》第3章花了不少篇幅讲基准测试,这篇文章帮你把方法论和实践结合起来。

基准测试的两种类型

全栈测试(Full-Stack Testing)

测试整个应用栈,从前端到数据库。优点是能发现各层之间的问题,缺点是需要完整的测试环境。

适用场景

  • 评估整体性能
  • 测试新版本升级
  • 容量规划

单组件测试(Single-Component Testing)

只测试MySQL本身。优点是环境简单,容易复现问题,缺点是忽略应用层的影响。

适用场景

  • 对比不同MySQL版本
  • 测试特定查询性能
  • 硬件选型对比

基准测试的设计原则

1. 使用真实数据

测试数据必须接近生产环境:

  • 数据量要相当(至少是生产环境的10%)
  • 数据分布要真实(不要全是测试数据)
  • 查询要真实(不要简化查询)

2. 使用真实查询

-- 错误示范:简化查询
SELECT * FROM users WHERE id = 1;

-- 正确做法:使用实际业务查询
SELECT u.*, o.* 
FROM users u 
LEFT JOIN orders o ON u.id = o.user_id 
WHERE u.status = 'active' 
  AND u.created_at > '2024-01-01'
ORDER BY u.last_login DESC 
LIMIT 100;

3. 预热(Warm-up)

测试前必须预热:

-- 执行典型的预热查询
SELECT COUNT(*) FROM large_table;
SELECT * FROM users WHERE id BETWEEN 1 AND 1000;
SELECT * FROM orders WHERE date >= CURDATE() - INTERVAL 30 DAY;

4. 多轮测试取平均

单次测试结果不可靠,至少跑3-5轮:

# 跑5轮,取平均值
for i in 1 2 3 4 5; do
    sysbench oltp_read_write run --threads=16 | grep -E 'queries:|tps:|latency:'
done

sysbench:最流行的MySQL基准测试工具

安装

# Ubuntu/Debian
apt-get install sysbench

# macOS
brew install sysbench

# 或者从源码编译
git clone https://github.com/akopytov/sysbench.git
./autogen.sh
./configure
make -j$(nproc)
make install

准备测试数据

# 创建10张表,每张表100万行数据
sysbench oltp_read_write \
    --db-driver=mysql \
    --mysql-host=localhost \
    --mysql-port=3306 \
    --mysql-user=sbtest \
    --mysql-password=password \
    --mysql-db=sbtest \
    --tables=10 \
    --table-size=1000000 \
    --threads=16 \
    prepare

执行测试

# OLTP读写混合测试(模拟真实业务)
sysbench oltp_read_write \
    --db-driver=mysql \
    --mysql-host=localhost \
    --mysql-port=3306 \
    --mysql-user=sbtest \
    --mysql-password=password \
    --mysql-db=sbtest \
    --tables=10 \
    --table-size=1000000 \
    --threads=16 \          # 16个并发线程
    --time=60 \             # 测试60秒
    --rate=0 \              # 0表示不限速,按最大能力跑
    run

# 只读测试(模拟报表查询)
sysbench oltp_read_only \
    --threads=32 \
    --time=60 \
    run

# 只写测试(模拟写入压力)
sysbench oltp_write_only \
    --threads=16 \
    --time=60 \
    run

解读测试结果

SQL statistics:
    queries performed: 1256847      # 总查询数
    reads: 8797931                  # 读操作数
    writes: 2094755                  # 写操作数
    other: 1675804                   # 其他操作(COMMIT等)
    transactions: 104672  (1744.44 per sec.)  # TPS
    queries: 1256847 (20953.12 per sec.)       # QPS
    latency events: 104672
    Avg: 9.17ms                     # 平均延迟
    95th percentile: 15.23ms        # 95百分位延迟
    max: 89.45ms                    # 最大延迟

关键指标解读

指标含义关注点
TPS每秒事务数越高越好
QPS每秒查询数越高越好
Avg latency平均延迟越低越好
95th percentile95%请求的延迟决定用户体验
max latency最大延迟关注异常值

清理测试数据

sysbench oltp_read_write \
    --db-driver=mysql \
    --mysql-db=sbtest \
    cleanup

不同场景的基准测试

场景1:评估服务器容量

# 从单线程开始,逐步增加并发
for threads in 1 2 4 8 16 32 64 128; do
    echo "=== Testing with $threads threads ==="
    sysbench oltp_read_write \
        --threads=$threads \
        --time=60 \
        --report-interval=5 \
        run | grep -E 'transactions:|queries:|latency:'
done

绘制并发数vs吞吐量的曲线,找到系统的拐点

场景2:对比InnoDB配置

# 测试前:innodb_buffer_pool_size = 1G
sysbench oltp_read_write --threads=16 run

# 修改配置后:innodb_buffer_pool_size = 4G
# 需要重启MySQL
sudo systemctl restart mysql

# 重新预热和测试
sysbench ... prepare
sleep 60  # 预热
sysbench oltp_read_write --threads=16 run

场景3:验证优化效果

-- 优化前:没有索引
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'paid';

-- 创建索引
CREATE INDEX idx_user_status ON orders(user_id, status);

-- 再次测试

场景4:压测极限

# 持续加压直到系统崩溃,记录临界点
sysbench oltp_read_write \
    --threads=256 \
    --time=300 \
    --forced-shutdown=5 \        # 测试结束后强制关闭
    run

# 观察:
# - 系统是否OOM
# - 连接数是否打满
# - 响应时间是否急剧上升

tpcc-mysql:TPC-C标准测试

TPC-C是OLTP领域的行业标准测试。

安装

git clone https://github.com/Percona-Lab/tpcc-mysql.git
cd tpcc-mysql/src
make

创建表结构

mysqladmin create tpcc1000

mysql -u root -p tpcc1000 < create_table.sql
mysql -u root -p tpcc1000 < add_fkey_idx.sql

加载数据

# 加载1000个仓库的数据(数据量较大,需要较长时间)
./tpcc_load localhost tpcc1000 root password 1000 10 10

# 参数说明:
# 1000: 仓库数(每个仓库约70MB数据)
# 10: 加载线程数
# 10: 预加载的数据

执行测试

./tpcc_start -h localhost -d tpcc1000 -u root -p password \
    -w 1000 -c 32 -r 300 -l 600 \
    -i 10 -f tpcc_result.txt

# 参数说明:
# -w 1000: 1000个仓库
# -c 32: 32个并发客户端
# -r 300: 预热300秒
# -l 600: 测试持续600秒
# -i 10: 每10秒报告一次
# -f: 结果输出到文件

TPC-C结果解读

TERMINATING 10, 000SCALE: 1000
Warmup: 300 sec
Measuring: 600 sec
90% response time: XX.XX ms
Around 10% response time: XX.XX ms
TpmC (NewOrders): XXXXX.XX

TpmC是TPC-C的核心指标,表示每分钟处理的新订单数。TpmC越高,系统处理OLTP事务的能力越强。

基准测试的常见误区

误区1:测试时间太短

# 错误:只跑10秒
--time=10

# 正确:至少跑60秒,足够系统稳定
--time=60

误区2:不预热就测试

冷缓存下的测试结果没有参考价值。

误区3:只看平均值

平均值会掩盖问题。一定要看百分位数

  • 50百分位:中位数用户体验
  • 95百分位:大多数用户的体验
  • 99百分位:最差1%用户

误区4:忽略网络延迟

如果应用和数据库不在同一台机器,测试时也要考虑网络开销。

误区5:单点测试

至少测试3次取平均值,剔除异常值。

基准测试 checklist

测试前检查清单:

  • MySQL配置已经过优化
  • 测试数据量接近生产
  • 已执行预热
  • 测试时间足够长(≥60秒)
  • 记录测试开始时的系统状态
  • 测试后确认无残留连接/进程

测试中监控:

  • CPU使用率
  • 内存使用
  • 磁盘I/O
  • 网络流量
  • MySQL连接数

小结

  1. 基准测试是科学,不是玄学:用真实数据、真实查询、多轮测试取平均
  2. sysbench是最常用的MySQL基准测试工具:适合快速验证
  3. TPC-C是OLTP标准测试:适合评估真实业务处理能力
  4. 关注百分位数:平均值会掩盖问题,95th percentile更能反映用户体验
  5. 找到系统拐点:并发数增加到一定程度后,吞吐量不再增加甚至下降,这就是拐点
  6. 记录一切:每次测试都要记录配置、数据量、结果,便于对比

基准测试的目的是回答"系统能做什么",而不是"系统做什么最快"。明确测试目标,选择合适的工具,设计合理的场景——这是性能优化的基本功。


上一篇【第06篇】Performance Schema详解——MySQL性能诊断神器

下一篇【第08篇】CPU与内存选型——MySQL服务器的硬件配置


延伸阅读