MySQL PreparedStatement 性能问题重现报告
1. 问题概述
1.1 问题描述
在 MySQL 使用 useServerPrepStmts=true 时,处理大量参数(5万个)的 PreparedStatement IN 查询时存在严重性能问题。根据原始报告,服务器端预编译比客户端预编译慢 190-207倍。
1.2 问题来源
1.3 问题根因(原始报告)
MySQL 服务器在处理大量参数的 PreparedStatement 时:
- 大量内存重分配: 50,000 次参数替换操作
- 字符串操作复杂度: O(SQL长度) × 参数数量
- 内存碎片化: 频繁的大块内存分配和释放
2. 测试环境
2.1 AWS 资源信息
| 资源 |
配置 |
| AWS Account |
872515255872 |
| Region |
ap-southeast-1 |
| VPC |
vpc-084114e405054a5b7 |
2.2 RDS MySQL 8.0 实例
| 配置项 |
值 |
| 实例标识符 |
mysql-prepared-test |
| 实例类型 |
db.t3.medium (2vCPU, 4GB) |
| 存储 |
50GB gp3 |
| 引擎版本 |
MySQL 8.0.43 |
| Endpoint |
mysql-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com |
2.3 RDS MySQL 5.7 实例
| 配置项 |
值 |
| 实例标识符 |
mysql57-prepared-test |
| 实例类型 |
db.t3.medium (2vCPU, 4GB) |
| 存储 |
50GB gp3 |
| 引擎版本 |
MySQL 5.7.44-rds.20240408 |
| Endpoint |
mysql57-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com |
2.4 EC2 测试客户端
| 配置项 |
值 |
| 实例 ID |
i-0b26f3cb781bae059 |
| 实例类型 |
t3.medium |
| AMI |
Amazon Linux 2023 |
| Public IP |
18.141.185.36 |
| Java |
Amazon Corretto 17 |
| Maven |
3.8.4 |
3. 测试方法
3.1 测试代码
1 2 3 4
| git clone https://github.com/plantegg/MySQLPrepared.git cd MySQLPrepared ./run_test.sh --host <mysql-host> --port 3306 --database test \ --user admin --password '<password>' --rounds 3
|
3.2 测试参数
| 参数 |
值 |
| IN 查询参数数量 |
50,000 |
| 参数类型 |
15位大整数 |
| SQL 长度 (spaces=128) |
~6.5MB |
| 测试轮次 |
3 |
3.3 AWS CLI 命令
创建 RDS MySQL 8.0 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| aws rds create-db-instance \ --profile default --region ap-southeast-1 \ --db-instance-identifier mysql-prepared-test \ --db-instance-class db.t3.medium \ --engine mysql \ --engine-version 8.0 \ --master-username admin \ --master-user-password 'Tiger#2612' \ --allocated-storage 50 \ --storage-type gp3 \ --db-subnet-group-name mysql-benchmark-subnet-group \ --vpc-security-group-ids sg-01541b078e0b483d0 \ --no-multi-az \ --publicly-accessible \ --backup-retention-period 0 \ --no-auto-minor-version-upgrade
|
创建 RDS MySQL 5.7 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| aws rds create-db-instance \ --profile default --region ap-southeast-1 \ --db-instance-identifier mysql57-prepared-test \ --db-instance-class db.t3.medium \ --engine mysql \ --engine-version 5.7.44-rds.20240408 \ --master-username admin \ --master-user-password 'Tiger#2612' \ --allocated-storage 50 \ --storage-type gp3 \ --db-subnet-group-name mysql-benchmark-subnet-group \ --vpc-security-group-ids sg-01541b078e0b483d0 \ --no-multi-az \ --publicly-accessible \ --backup-retention-period 0 \ --no-auto-minor-version-upgrade
|
创建 EC2 测试实例
1 2 3 4 5 6 7 8
| aws ec2 run-instances \ --profile default --region ap-southeast-1 \ --image-id ami-0d1c0ec9903f7b01f \ --instance-type t3.medium \ --key-name renxijun-ec2-key \ --security-group-ids sg-0706d5fbe75649370 \ --subnet-id subnet-09d864b724dce6434 \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=mysql-prepared-test-ec2}]'
|
4. 测试结果
4.1 MySQL 8.0.43 测试结果
紧凑格式 (spaces=0, SQL长度 ~100KB)
| 配置 |
平均执行时间 |
Com_stmt_prepare |
| useServerPrepStmts=false |
129.6ms |
0 |
| useServerPrepStmts=true |
115.6ms |
1 |
| 性能差异 |
true 快 1.1 倍 |
- |
带空格格式 (spaces=128, SQL长度 ~6.5MB)
| 配置 |
平均执行时间 |
Com_stmt_prepare |
| useServerPrepStmts=false |
400.7ms |
0 |
| useServerPrepStmts=true |
101.0ms |
1 |
| 性能差异 |
true 快 4.0 倍 |
- |
4.2 MySQL 5.7.44 测试结果
带空格格式 (spaces=128, SQL长度 ~6.5MB)
| 配置 |
平均执行时间 |
Com_stmt_prepare |
| useServerPrepStmts=false |
600.0ms |
0 |
| useServerPrepStmts=true |
90.0ms |
1 |
| 性能差异 |
true 快 6.7 倍 |
- |
4.3 与原始报告对比
| 版本 |
原始报告 (5.7.29) |
本次测试 (5.7.44) |
本次测试 (8.0.43) |
| false 平均时间 |
~52ms |
600ms |
400.7ms |
| true 平均时间 |
~27,839ms |
90ms |
101ms |
| 性能差异 |
true 慢 535 倍 |
true 快 6.7 倍 |
true 快 4.0 倍 |
5. 结论
5.1 问题重现结果
在 MySQL 5.7.44 和 8.0.43 版本上,原始报告中描述的性能问题未能重现。
测试结果显示:
- 在两个版本上,
useServerPrepStmts=true 反而比 false 更快
- MySQL 5.7.44: 服务器端预编译快 6.7 倍
- MySQL 8.0.43: 服务器端预编译快 4.0 倍
5.2 可能原因分析
MySQL 版本差异
- 原始问题发现于 MySQL 5.7.29
- 本次测试使用 MySQL 5.7.44 和 8.0.43
- 问题可能已在 5.7.29 之后的版本中被修复
AWS RDS 优化
- AWS RDS 可能包含特定的性能优化
- 与原生 MySQL 行为可能存在差异
JDBC 驱动版本
- 测试使用 mysql-connector-j-8.0.33
- 驱动可能已优化参数处理逻辑
5.3 建议
如需重现原始问题
- 使用 MySQL 5.7.29 或更早版本
- 使用原生 MySQL 而非 AWS RDS
生产环境建议
- 在较新版本的 MySQL 上,
useServerPrepStmts=true 性能更优
- 建议进行实际业务场景的性能测试
- 对于大量参数的 IN 查询,考虑使用分批查询或临时表方案
6. 附录
6.1 测试日志
MySQL 8.0.43 完整输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| === MySQL PreparedStatement性能对比测试 === 连接信息: mysql-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com:3306/test 参数数量: 50000 测试轮次: 3
测试配置: useServerPrepStmts=false 参数空格数: 128 SQL长度: 6500023 字符 执行第1次查询... 第1次: 571ms (返回0条记录) 执行第2次查询... 第2次: 317ms (返回0条记录) 执行第3次查询... 第3次: 314ms (返回0条记录)
=== useServerPrepStmts=false 测试结果 === 总执行时间: 1202ms 平均执行时间: 400.7ms 返回记录数: 0 Com_stmt_prepare: 0 -> 0
测试配置: useServerPrepStmts=true 参数空格数: 128 SQL长度: 6500023 字符 执行第1次查询... 第1次: 138ms (返回0条记录) 执行第2次查询... 第2次: 92ms (返回0条记录) 执行第3次查询... 第3次: 73ms (返回0条记录)
=== useServerPrepStmts=true 测试结果 === 总执行时间: 303ms 平均执行时间: 101.0ms 返回记录数: 0 Com_stmt_prepare: 0 -> 1
|
MySQL 5.7.44 完整输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| === MySQL PreparedStatement性能对比测试 === 连接信息: mysql57-prepared-test.cfsoq6muu0jv.ap-southeast-1.rds.amazonaws.com:3306/test 参数数量: 50000 测试轮次: 3
测试配置: useServerPrepStmts=false 参数空格数: 128 SQL长度: 6500023 字符 执行第1次查询... 第1次: 639ms (返回0条记录) 执行第2次查询... 第2次: 681ms (返回0条记录) 执行第3次查询... 第3次: 480ms (返回0条记录)
=== useServerPrepStmts=false 测试结果 === 总执行时间: 1800ms 平均执行时间: 600.0ms 返回记录数: 0 Com_stmt_prepare: 0 -> 0
测试配置: useServerPrepStmts=true 参数空格数: 128 SQL长度: 6500023 字符 执行第1次查询... 第1次: 117ms (返回0条记录) 执行第2次查询... 第2次: 77ms (返回0条记录) 执行第3次查询... 第3次: 76ms (返回0条记录)
=== useServerPrepStmts=true 测试结果 === 总执行时间: 270ms 平均执行时间: 90.0ms 返回记录数: 0 Com_stmt_prepare: 0 -> 1
|
6.2 参考资料
报告生成时间: 2026-01-12
测试执行者: Kiro CLI
AWS Account: 872515255872