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

在后端开发中,我们常遇到一种场景: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 的"生成测试数据"功能,可替代手写脚本的繁琐过程。

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

相关推荐
helloworld工程师1 小时前
Dubbo应用开发之基于Dubbo协议的springboot规范性开发
spring boot·后端·dubbo
码途进化论1 小时前
前端Docker多平台构建自动化实践
前端·javascript·后端
悟空码字1 小时前
SpringBoot 整合 RabbitMQ:和这只“兔子”交朋友
java·后端·rabbitmq
BingoGo2 小时前
万物皆字符串 PHP 中的原始类型偏执
后端·php
Carve_the_Code2 小时前
订单ID容量升级:从40位到64位的架构演进
后端
一粒麦仔2 小时前
物联网的低功耗守望者:全面解析Sigfox技术
后端·网络协议
Frank_zhou2 小时前
192_如何基于复杂的指针移动完成单向链表的入队?
后端
Frank_zhou2 小时前
03_ArrayList核心方法的原理
后端
HLeo2 小时前
一段代码演示初学者容易掉坑的“comptime 副作用陷阱”
后端