一个比脚本造数据更快的方式-存储过程
存储过程造数据主要有以下几个优势:
1.批量高效
一次性插入大量数据,比逐条执行INSERT快得多。比如造 10 万条测试数据,用存储过程几秒就完成,手写 SQL 几乎不可能。
2.逻辑可复用
一次创建,多次调用:
CALLgenerate_test_bonds(100);-- 造 100 条CALLgenerate_test_bonds(10000);-- 造 1 万条3.数据可控
可以灵活控制数据量和数据模式,比如模拟真实场景:
- 少量数据测功能正确性
- 大量数据测性能、索引优化、分页查询
4.SQL 运行在服务端
存储过程在 MySQL 服务器端执行,网络开销小,不会有大量 SQL 语句来回传输。
对比:
| 方式 | 1 万条数据耗时 | 灵活性 |
|---|---|---|
逐条INSERT | 慢,多次网络往返 | 低 |
| 存储过程 | 快,服务端一次性执行 | 高,传参控制 |
| 脚本语言(Python/Shell) | 中等 | 最高 |
存储过程详解
什么是存储过程?
存储过程(Stored Procedure)是一组预编译的 SQL 语句集合,存储在数据库服务器上,通过一个名称调用执行。可以理解为"数据库里的函数"。
以你的代码为例逐行解析
DELIMITER// -- 1. 临时修改语句结束符为 //CREATEPROCEDUREgenerate_test_bonds(INnumINT)-- 2. 创建存储过程,接收一个输入参数BEGIN-- 3. 过程体开始DECLAREiINTDEFAULT1;-- 4. 声明局部变量 i,初始值 1WHILEi<=numDO-- 5. 循环条件:i <= 传入的参数INSERTINTObond_info(bond_code,bond_name,price,status)VALUES(CONCAT('BOND',LPAD(i,6,'0')),-- 生成 BOND000001 格式的代码CONCAT('测试债券',i),-- 生成"测试债券1"格式的名称ROUND(RAND()*100,2),-- 随机生成 0~100 的价格,保留2位小数'ACTIVE');-- 固定状态值SETi=i+1;-- 6. 计数器 +1ENDWHILE;-- 7. 循环结束END// -- 8. 过程体结束DELIMITER;-- 9. 恢复语句结束符为 ;语法说明
1.DELIMITER— 为什么需要它?
默认情况下 MySQL 用;作为语句结束符。但存储过程内部包含多条;结尾的语句,如果不改分隔符,MySQL 遇到第一个;就认为结束了。
DELIMITER // ← 告诉 MySQL:现在用 // 当作结束符 ...存储过程内容(里面可以正常用 ;)... END // ← 这里才真正结束 DELIMITER ; ← 恢复默认2. 参数类型
| 类型 | 含义 | 示例 |
|---|---|---|
IN | 输入参数,调用时传入 | IN num INT |
OUT | 输出参数,过程内赋值,调用后取出 | OUT total INT |
INOUT | 输入输出兼顾 | INOUT val INT |
3. 变量
DECLAREiINTDEFAULT1;-- 声明 + 默认值SETi=i+1;-- 赋值SELECTCOUNT(*)INTOiFROMbond_info;-- 查询结果赋给变量4. 流程控制
-- 条件判断IF条件THEN...ELSEIF条件THEN...ELSE...ENDIF;-- 循环WHILE条件DO...ENDWHILE;REPEAT...UNTIL 条件ENDREPEAT;完整生命周期
创建 → 调用 → 查看 → 删除 CREATE PROCEDURE xxx() ... -- 创建 CALL xxx(); -- 调用 SHOW CREATE PROCEDURE xxx; -- 查看定义 DROP PROCEDURE IF EXISTS xxx; -- 删除优缺点
| 优点 | 缺点 |
|---|---|
| 预编译,执行快 | 调试困难 |
| 减少网络传输 | 移植性差(不同数据库语法不同) |
| 逻辑封装,复用方便 | 版本管理不方便 |
| 安全性高(权限控制) | 复杂业务逻辑不适合全放数据库 |
总之:造测试数据用存储过程是最省事、最高效的方式。
