MySQL PreparedStatement 性能问题重现报告

MySQL PreparedStatement 性能问题重现报告

1. 问题概述

1.1 问题描述

在 MySQL 使用 useServerPrepStmts=true 时,处理大量参数(5万个)的 PreparedStatement IN 查询时存在严重性能问题。根据原始报告,服务器端预编译比客户端预编译慢 190-207倍

1.2 问题来源

1.3 问题根因(原始报告)

MySQL 服务器在处理大量参数的 PreparedStatement 时:

  1. 大量内存重分配: 50,000 次参数替换操作
  2. 字符串操作复杂度: O(SQL长度) × 参数数量
  3. 内存碎片化: 频繁的大块内存分配和释放

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 可能原因分析

  1. MySQL 版本差异

    • 原始问题发现于 MySQL 5.7.29
    • 本次测试使用 MySQL 5.7.44 和 8.0.43
    • 问题可能已在 5.7.29 之后的版本中被修复
  2. AWS RDS 优化

    • AWS RDS 可能包含特定的性能优化
    • 与原生 MySQL 行为可能存在差异
  3. JDBC 驱动版本

    • 测试使用 mysql-connector-j-8.0.33
    • 驱动可能已优化参数处理逻辑

5.3 建议

  1. 如需重现原始问题

    • 使用 MySQL 5.7.29 或更早版本
    • 使用原生 MySQL 而非 AWS RDS
  2. 生产环境建议

    • 在较新版本的 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