sql批量生成测试数据的核心是利用递归CTE、系统表笛卡尔积或存储过程分批插入,结合随机函数与业务规则(如预设城市列表、手机号格式、状态比例)构造真实感数据,适配不同数据库语法特性。

用SQL批量生成测试数据,核心是利用数据库的递归、循环或系统表特性,快速构造出符合业务逻辑的模拟数据,不用写脚本、不依赖外部工具。
用递归CTE生成连续编号或时间序列
适合造用户ID、订单号、日期维度等有规律的数据。以postgresql或SQL Server为例:
- 生成1~10000的用户ID和随机姓名:
WITH users AS (
select 1 AS id, ‘User_’ || floor(random() * 1000)::text AS name
union ALL
SELECT id + 1, ‘User_’ || floor(random() * 1000)::text
FROM users
WHERE id )
INSERT intO user_table (id, name) SELECT id, name FROM users;
注意:mysql 8.0+ 支持CTE,旧版可用INSERT ... SELECT配合numbers辅助表;递归深度需留意(如SQL Server默认100,可加OPTION (MAXRECURSION 10000))。
用系统表或笛卡尔积放大行数
没有递归支持时(如MySQL 5.7),可借INFORMATION_SCHEMA.COLUMNS等自带多行的系统表“凑数”:
- 生成约1万行(取前100列 × 前100列):
INSERT INTO order_table (order_no, amount, create_time)
SELECT
CONCAT(‘ORD_’, LPAD(@row:=@row+1, 6, ‘0’)),
ROUND(RAND() * 999.99, 2),
DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 365) DAY)
FROM INFORMATION_SCHEMA.COLUMNS t1
CROSS JOIN INFORMATION_SCHEMA.COLUMNS t2
CROSS JOIN (SELECT @row := 0) r
LIMIT 10000;
关键是用CROSS JOIN制造组合爆炸,再用LIMIT截断;变量@row用于生成唯一编号。
按业务规则注入真实感字段
单纯随机数不够像真数据。可结合CASE、字符串函数、固定列表提升可信度:
- 城市字段从预设列表中随机选:
ELT(FLOOR(1 + RAND() * 5), '北京', '上海', '广州', '深圳', '杭州')- 手机号用前缀+8位随机数:
CONCAT('13', LPAD(FLOOR(RAND() * 100000000), 8, '0')) - 状态字段按比例分布:
CASE WHEN RAND()
避免所有字段都用RAND(),否则容易出现逻辑矛盾(比如“已完成”订单却无支付时间),建议先定主干字段(如status),再条件生成关联字段。
一次性插入 vs 分批提交防锁表
生成超10万行时,单条INSERT可能卡住或OOM。稳妥做法是分批次:
- 每5000行提交一次(以MySQL为例):
DELIMITER $$
CREATE PROCEDURE gen_test_data()
BEGIN
DECLARE i INT default 1;
while i INSERT INTO log_table (…) SELECT … FROM … LIMIT 5000 OFFSET i-1;
COMMIT;
SET i = i + 5000;
END WHILE;
END$$
DELIMITER ;
CALL gen_test_data();
或者用应用层控制(python/Shell调用多条INSERT),更灵活也更易中断重试。
基本上就这些——不需要框架、不写java/Python,纯SQL就能把测试环境撑起来。关键在理解自己用的数据库支持什么语法,再把“生成逻辑”拆成可叠加的简单步骤。