生成测试数据(一):分钟级构建百万级数据,测试数据库性能

在后端开发中,我们常遇到一种场景:SQL 在本地开发环境(只有几百条数据)跑得飞快,一上线遇到生产环境(百万/千万级数据)就直接卡死甚至拖垮数据库。

核心原因在于"空表陷阱":当表数据量过少时,MySQL 优化器往往会直接选择全表扫描(Full Table Scan),因为此时扫描全表的成本比走索引(Index Dive + 回表)更低。这导致我们在开发阶段无法通过 EXPLAIN 发现潜在的慢查询(Slow SQL)。

要解决这个问题,必须在开发/测试环境构建"等量级"甚至"超量级"的仿真数据。

传统做法是写脚本或存储过程循环插入,但存在单线程慢、容易锁表、代码维护麻烦等问题。本文分享一个在 SQLynx 中利用内置功能,通过配置事务与批量提交策略,快速生成百万级压测数据的技巧。

01 场景准备

假设我们有一张 t_orders 表,这是最常见的需要做性能优化的场景。

sql 复制代码
CREATE TABLE `t_orders` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `order_no` varchar(32) NOT NULL COMMENT '订单号',
  `amount` decimal(10,2) NOT NULL COMMENT '金额',
  `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态:0-待付,1-已付,2-发货,3-完成',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_time` (`user_id`,`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我们的目标是:往这张表里快速灌入 100 万条数据,且数据分布要尽量符合真实业务场景(有离散度),以验证 idx_user_time 索引的有效性。

02 测试数据配置

在 SQLynx 中选中表 t_orders,右键选择 "生成测试数据"

这里不需要写代码,为了让测试结果真实,需要在弹窗中针对字段类型做如下配置:

  • user_id(模拟高离散度):

  • 设置生成模式为"随机整数"。

  • 范围设为 1000 - 50000。

  • 技术解读: 模拟 5 万个不同用户的下单行为,测试索引的选择性。

  • amount(模拟金额):

  • 设置生成模式为"随机浮点数"。

  • 范围 10.00 - 5000.00。

  • status(模拟低离散度):

  • 设置生成模式为"随机整数"。

  • 范围 0 - 3。

  • 技术解读: 状态字段通常基数很小,用于测试索引失效的边界情况。

03 事务与批量大小

这是从"慢速插入"到"极速写入"的关键一步。

如果在循环中每插入一条数据就 Commit 一次,100 万次网络 IO 和 100 万次 Binlog/Redo Log 刷盘会让写入速度极慢。

在配置界面,我们需要调整写入策略

  1. 执行模式: 选择 "事务执行"
  2. 批量大小: 可从 1000 开始逐步递增,测试最适合自己环境的最佳数值(如2000-5000的区间值)

为什么要这样设?

  • 减少 IO 开销: 设置 Batch=1000,意味着每 1000 条 INSERT 语句合并为一个网络包发送,且只进行一次磁盘刷盘。
  • 避免长事务: 避免直接设置数值过大,如100000。过大的 Batch 会导致 Undo Log 膨胀,甚至可能触碰 MySQL 的 max_allowed_packet 限制导致报错。
  • 模式选择: 选择 "追加数据"

点击"确认",进入任务中心查看进度。通常在内网环境下,百万级数据的生成在几十秒~分钟级可完成。

04 验证效果:从 ALL 到 ref

数据到位后,我们可以进行测试。

测试 SQL: 查询某个用户最近的订单。

sql 复制代码
SELECT * FROM t_orders WHERE user_id = 10086 ORDER BY create_time DESC LIMIT 10;

场景 A:数据量 100 条(模拟开发环境)

执行 EXPLAIN,你可能会看到 type: ALL(全表扫描)。

  • 现象: 耗时 0.00ms。
  • 隐患: 开发者误以为性能完美。实际上是因为数据量太小,MySQL 优化器认为全表扫描成本低于读取索引树,因此主动放弃了索引。这掩盖了潜在的性能问题。

场景 B:数据量 100 万条(测试数据生成后)

再次执行 EXPLAIN。

  • type: ref:全表扫描(ALL)消失了,key 字段显示为 idx_user_time,说明索引被命中。

  • rows: 21:我们设置的用户 ID 范围是 1000-50000(基数约 4.9 万)。

  • 验证: 总行数 100 万 / 用户基数 4.9 万 ≈ 20.4 行。

  • 结论: rows: 21 与理论值一致。这证明了生成的随机数据具有均匀分布特性,没有出现数据倾斜。这种高离散度的数据真实还原了生产环境,验证了索引的高选择性。

05 总结

"造数"是后端开发和 DBA 的一项基础设施能力。

利用 SQLynx 的"生成测试数据"功能,可替代手写脚本的繁琐过程。

对于技术人员来说,在实际测试环境中,需要面对百万级、千万级数据的压测,采用便捷稳定的工具可有效帮助工作效率提升,是避免线上故障的最低成本路径。

相关推荐
NAGNIP13 小时前
多个 GitHub 账户SSH 密钥配置全攻略
后端
NAGNIP13 小时前
Windows命令行代码自动补全详细步骤
后端
追逐时光者14 小时前
精选 8 款 .NET 开源、前后端分离的快速开发框架,提高开发生产效率!
后端·.net
用户479492835691514 小时前
性能提升 4000%!我是如何解决 运营看板 不能跨库&跨库查询慢这个难题的
数据库·后端·postgresql
老华带你飞15 小时前
农产品销售管理|基于java + vue农产品销售管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
短剑重铸之日16 小时前
SpringBoot声明式事务的源码解析
java·后端·spring·springboot
JIngJaneIL16 小时前
基于springboot + vue房屋租赁管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
wadesir17 小时前
Go语言中高效读取数据(详解io包的ReadAll函数用法)
开发语言·后端·golang
千寻技术帮17 小时前
10422_基于Springboot的教务管理系统
java·spring boot·后端·vue·教务管理
Victor35617 小时前
Hibernate(12)什么是Hibernate的实体类?
后端