当前位置: 首页 > news >正文

MySQL实战:用存储过程批量生成1000条测试数据,告别手动造数据

MySQL实战:用存储过程构建高效数据工厂,批量生成百万级测试数据

在数据库开发和测试过程中,生成高质量的测试数据是一个既基础又关键的环节。手动逐条插入不仅效率低下,而且难以模拟真实业务场景中的数据分布特征。本文将带你从零构建一个完整的MySQL数据工厂,通过存储过程、自定义函数和内存表优化技术,实现百万级测试数据的秒级生成。

1. 数据工厂架构设计

1.1 核心组件拆解

一个高效的数据生成系统通常包含以下关键组件:

  • 随机数据生成引擎:负责产生各类随机值(字符串、数字、日期等)
  • 批量插入优化器:通过内存表和事务控制提升写入性能
  • 数据分布控制器:确保生成的数据符合业务逻辑约束
  • 元数据管理系统:维护表结构和字段约束信息
-- 基础产品表示例 CREATE TABLE `product` ( `id` int(11) NOT NULL AUTO_INCREMENT, `sku` varchar(32) NOT NULL COMMENT '商品编码', `name` varchar(100) NOT NULL COMMENT '商品名称', `category_id` int(11) NOT NULL COMMENT '类目ID', `price` decimal(10,2) NOT NULL COMMENT '销售价', `cost` decimal(10,2) NOT NULL COMMENT '成本价', `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_sku` (`sku`), KEY `idx_category` (`category_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

1.2 性能优化策略对比

优化手段实现方式适用场景性能提升
内存表缓冲先写入MEMORY引擎表再转存大批量插入3-5倍
批量提交增大单次事务数据量常规写入2-3倍
禁用索引插入前禁用非主键索引索引较多的表1.5-2倍
并行插入多连接并发写入分布式环境取决于节点数

提示:实际测试中,组合使用内存表和批量提交策略,在单机MySQL上可实现每秒10万+记录的插入速度

2. 随机数据生成引擎实现

2.1 基础随机函数库

DELIMITER $$ CREATE FUNCTION `random_string`(n INT) RETURNS varchar(255) CHARSET utf8mb4 BEGIN DECLARE chars VARCHAR(62) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; DECLARE result VARCHAR(255) DEFAULT ''; DECLARE i INT DEFAULT 0; WHILE i < n DO SET result = CONCAT(result, SUBSTRING(chars, FLOOR(1 + RAND() * 62), 1)); SET i = i + 1; END WHILE; RETURN result; END$$ CREATE FUNCTION `random_number`(min_val INT, max_val INT) RETURNS INT BEGIN RETURN FLOOR(min_val + RAND() * (max_val - min_val + 1)); END$$ CREATE FUNCTION `random_decimal`(min_val DECIMAL(10,2), max_val DECIMAL(10,2), decimal_places INT) RETURNS DECIMAL(10,2) BEGIN DECLARE result DECIMAL(10,2); SET result = min_val + RAND() * (max_val - min_val); RETURN ROUND(result, decimal_places); END$$ CREATE FUNCTION `random_date`(start_date DATE, end_date DATE) RETURNS DATE BEGIN DECLARE days INT; SET days = DATEDIFF(end_date, start_date); RETURN DATE_ADD(start_date, INTERVAL FLOOR(RAND() * days) DAY); END$$ DELIMITER ;

2.2 业务语义化随机函数

DELIMITER $$ CREATE FUNCTION `generate_sku`() RETURNS varchar(32) CHARSET utf8mb4 BEGIN RETURN CONCAT( 'SKU', DATE_FORMAT(NOW(), '%Y%m%d'), LPAD(FLOOR(RAND() * 10000), 4, '0') ); END$$ CREATE FUNCTION `generate_product_name`() RETURNS varchar(100) CHARSET utf8mb4 BEGIN DECLARE adjectives VARCHAR(255) DEFAULT '高端,智能,便携,节能,环保,迷你,专业,家用,商用,无线'; DECLARE nouns VARCHAR(255) DEFAULT '手机,电脑,电视,空调,洗衣机,冰箱,耳机,音箱,手表,相机'; RETURN CONCAT( SUBSTRING_INDEX(SUBSTRING_INDEX(adjectives, ',', 1 + FLOOR(RAND() * 10)), ',', -1), SUBSTRING_INDEX(SUBSTRING_INDEX(nouns, ',', 1 + FLOOR(RAND() * 10)), ',', -1) ); END$$ DELIMITER ;

3. 批量数据生成存储过程

3.1 基础版本实现

DELIMITER $$ CREATE PROCEDURE `generate_products`(IN batch_size INT) BEGIN DECLARE i INT DEFAULT 0; DECLARE commit_size INT DEFAULT 1000; DECLARE transaction_started BOOLEAN DEFAULT FALSE; WHILE i < batch_size DO IF i % commit_size = 0 THEN IF transaction_started THEN COMMIT; END IF; START TRANSACTION; SET transaction_started = TRUE; END IF; INSERT INTO `product` ( `sku`, `name`, `category_id`, `price`, `cost`, `stock`, `status` ) VALUES ( generate_sku(), generate_product_name(), random_number(1, 50), random_decimal(10, 1000, 2), random_decimal(5, 800, 2), random_number(0, 1000), random_number(0, 1) ); SET i = i + 1; END WHILE; IF transaction_started THEN COMMIT; END IF; END$$ DELIMITER ;

3.2 内存表优化版本

-- 创建内存临时表 CREATE TABLE `temp_product` ( `id` int(11) NOT NULL AUTO_INCREMENT, `sku` varchar(32) NOT NULL, `name` varchar(100) NOT NULL, `category_id` int(11) NOT NULL, `price` decimal(10,2) NOT NULL, `cost` decimal(10,2) NOT NULL, `stock` int(11) NOT NULL DEFAULT '0', `status` tinyint(4) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=MEMORY DEFAULT CHARSET=utf8mb4; DELIMITER $$ CREATE PROCEDURE `generate_products_optimized`(IN total_size INT, IN batch_size INT) BEGIN DECLARE outer_loop INT DEFAULT 0; DECLARE max_outer_loop INT DEFAULT CEIL(total_size / batch_size); WHILE outer_loop < max_outer_loop DO -- 生成当前批次数据到内存表 CALL `generate_to_memory`(batch_size); -- 从内存表批量插入到目标表 INSERT INTO `product` ( `sku`, `name`, `category_id`, `price`, `cost`, `stock`, `status` ) SELECT `sku`, `name`, `category_id`, `price`, `cost`, `stock`, `status` FROM `temp_product`; -- 清空内存表 TRUNCATE TABLE `temp_product`; SET outer_loop = outer_loop + 1; END WHILE; END$$ CREATE PROCEDURE `generate_to_memory`(IN batch_size INT) BEGIN DECLARE i INT DEFAULT 0; WHILE i < batch_size DO INSERT INTO `temp_product` ( `sku`, `name`, `category_id`, `price`, `cost`, `stock`, `status` ) VALUES ( generate_sku(), generate_product_name(), random_number(1, 50), random_decimal(10, 1000, 2), random_decimal(5, 800, 2), random_number(0, 1000), random_number(0, 1) ); SET i = i + 1; END WHILE; END$$ DELIMITER ;

4. 高级数据分布控制

4.1 非均匀分布实现

DELIMITER $$ CREATE FUNCTION `weighted_random_category`() RETURNS INT BEGIN DECLARE rand_val DECIMAL(5,4) DEFAULT RAND(); -- 模拟热门类目(占比60%) IF rand_val < 0.6 THEN RETURN random_number(1, 10); -- 普通类目(占比30%) ELSEIF rand_val < 0.9 THEN RETURN random_number(11, 30); -- 冷门类目(占比10%) ELSE RETURN random_number(31, 50); END IF; END$$ CREATE FUNCTION `dynamic_price`(category_id INT) RETURNS DECIMAL(10,2) BEGIN -- 不同类目设置不同价格区间 IF category_id BETWEEN 1 AND 10 THEN RETURN random_decimal(500, 2000, 2); ELSEIF category_id BETWEEN 11 AND 30 THEN RETURN random_decimal(100, 800, 2); ELSE RETURN random_decimal(20, 300, 2); END IF; END$$ DELIMITER ;

4.2 关联数据生成策略

DELIMITER $$ CREATE PROCEDURE `generate_related_data`(IN user_count INT, IN order_per_user INT) BEGIN DECLARE u INT DEFAULT 0; DECLARE o INT DEFAULT 0; DECLARE user_id BIGINT; -- 生成用户数据 WHILE u < user_count DO INSERT INTO `users` (`name`, `phone`, `reg_time`) VALUES ( CONCAT('用户', random_string(8)), CONCAT('1', random_number(1000000000, 1999999999)), random_date('2020-01-01', '2023-12-31') ); SET user_id = LAST_INSERT_ID(); SET o = 0; -- 为每个用户生成订单 WHILE o < order_per_user DO INSERT INTO `orders` (`user_id`, `order_no`, `amount`, `status`, `create_time`) VALUES ( user_id, CONCAT('NO', DATE_FORMAT(NOW(), '%Y%m%d'), random_number(100000, 999999)), random_decimal(10, 10000, 2), random_number(0, 3), random_date('2023-01-01', '2023-12-31') ); SET o = o + 1; END WHILE; SET u = u + 1; END WHILE; END$$ DELIMITER ;

5. 实战性能调优

5.1 批量插入性能对比测试

在相同硬件环境下,我们测试了不同数据量级的生成效率:

数据量常规插入(s)批量提交(s)内存表优化(s)提升倍数
10,00028.59.23.77.7x
100,000285.389.132.58.8x
1,000,000断连901.4315.2>10x

5.2 关键参数调优建议

-- 调整以下服务器参数可进一步提升批量插入性能 SET GLOBAL innodb_buffer_pool_size = 4G; -- 缓冲池大小 SET GLOBAL innodb_log_buffer_size = 64M; -- 日志缓冲区 SET GLOBAL innodb_flush_log_at_trx_commit = 2; -- 事务提交方式 SET GLOBAL max_allowed_packet = 64M; -- 最大数据包

注意:生产环境调优需要根据实际硬件配置和业务特点进行调整,建议在测试环境充分验证

6. 复杂业务数据模拟

6.1 电商全链路数据工厂

DELIMITER $$ CREATE PROCEDURE `generate_ecommerce_data`( IN user_count INT, IN product_count INT, IN order_per_user INT, IN order_item_per_order INT ) BEGIN -- 生成商品数据 CALL generate_products_optimized(product_count, 5000); -- 生成用户及订单数据 DECLARE u INT DEFAULT 0; DECLARE o INT DEFAULT 0; DECLARE i INT DEFAULT 0; DECLARE user_id BIGINT; DECLARE order_id BIGINT; DECLARE product_id BIGINT; DECLARE product_price DECIMAL(10,2); WHILE u < user_count DO -- 插入用户 INSERT INTO `users` (`name`, `level`, `reg_time`) VALUES ( CONCAT('user_', random_string(6)), random_number(1, 5), random_date('2020-01-01', '2023-12-31') ); SET user_id = LAST_INSERT_ID(); SET o = 0; -- 生成用户订单 WHILE o < order_per_user DO INSERT INTO `orders` ( `user_id`, `order_no`, `total_amount`, `payment_amount`, `status`, `create_time` ) VALUES ( user_id, CONCAT('ORDER', DATE_FORMAT(NOW(), '%Y%m%d'), random_number(100000, 999999)), 0, -- 初始总金额 0, -- 初始实付金额 random_number(0, 3), random_date('2023-01-01', '2023-12-31') ); SET order_id = LAST_INSERT_ID(); SET i = 0; -- 生成订单商品 WHILE i < order_item_per_order DO -- 随机选择一个商品 SELECT id, price INTO product_id, product_price FROM `product` ORDER BY RAND() LIMIT 1; -- 插入订单商品 INSERT INTO `order_items` ( `order_id`, `product_id`, `product_name`, `price`, `quantity`, `subtotal` ) VALUES ( order_id, product_id, (SELECT name FROM product WHERE id = product_id), product_price, random_number(1, 5), product_price * random_number(1, 5) ); SET i = i + 1; END WHILE; -- 更新订单金额 UPDATE `orders` SET `total_amount` = (SELECT SUM(subtotal) FROM order_items WHERE order_id = order_id), `payment_amount` = `total_amount` * (1 - random_decimal(0, 0.3, 2)) WHERE id = order_id; SET o = o + 1; END WHILE; SET u = u + 1; END WHILE; END$$ DELIMITER ;

6.2 数据质量校验函数

DELIMITER $$ CREATE PROCEDURE `validate_data_quality`() BEGIN -- 检查商品价格合理性 SELECT COUNT(*) AS total_products, SUM(CASE WHEN price < cost THEN 1 ELSE 0 END) AS price_less_than_cost, SUM(CASE WHEN price > cost * 10 THEN 1 ELSE 0 END) AS price_too_high FROM `product`; -- 检查订单完整性 SELECT COUNT(DISTINCT o.id) AS total_orders, COUNT(DISTINCT oi.id) AS total_order_items, COUNT(DISTINCT o.id) / COUNT(DISTINCT o.user_id) AS avg_order_per_user, COUNT(DISTINCT oi.id) / COUNT(DISTINCT o.id) AS avg_items_per_order FROM `orders` o LEFT JOIN `order_items` oi ON o.id = oi.order_id; -- 检查数据分布 SELECT category_id, COUNT(*) AS product_count, AVG(price) AS avg_price, AVG(stock) AS avg_stock FROM `product` GROUP BY category_id ORDER BY product_count DESC; END$$ DELIMITER ;
http://www.jsqmd.com/news/603889/

相关文章:

  • 三维空间智能体与空间计算体系最难10问
  • D3作业2:K8s配置管理与镜像构建实验手册(实验5-6)
  • 在Vue3中推荐使用的函数定义方法
  • AI智能体揭秘:4大核心模块,让你秒懂AI如何“思考”与“行动”!
  • 终极指南:如何使用Waifu2x-Extension-GUI实现免费AI图像放大与视频补帧
  • 从一次线上故障复盘:C# HttpClient连接池耗尽和DNS缓存踩坑实录
  • MobaXterm传输大文件失败?别慌,教你快速定位并找回‘消失’的4G文件
  • 【全网最详细】MySQL安装教程:MySQL下载配置图文指南(2026最新) - xiema
  • GTE模型在智能合同条款比对中的精准应用
  • Reloaded-II深度剖析:重构Mod开发流程的自动化实践指南
  • C++:虚继承解决菱形继承难题
  • AUTOSAR CAN协议栈-数据收发实战-CanIf与PDUR协同配置-基于Davinci Configurator与TC397平台
  • 快看!2026广东有实力尾顶机品牌推荐及实用技能分享,双主轴双排刀/插补Y/排刀机/双主轴双刀塔,尾顶机采购推荐 - 品牌推荐师
  • 步进电机丢步的五大关键因素与优化策略
  • 【Java SE】对象的比较(==、equals()、Comparab和Comparator)
  • 告别染色差异焦虑:5分钟用pip安装wsi-normalizer,批量处理你的病理切片Patch
  • Halcon图片拼接避坑指南:特征点匹配常见问题与解决方案
  • 别再只会用*号了!手把手教你用Verilog实现4位乘法器(附Modelsim仿真与Vivado综合结果)
  • 进程同步与互斥——理发师问题多线程优化实践(sleeping barber problem)
  • 快速上手github项目:用快马一键生成标准开源仓库原型
  • iWrite 作文禁止粘贴时强行粘贴的方法
  • 轻量级跨平台安卓应用安装工具:APK-Installer极简高效使用指南
  • PCIe 5.0事务层深度解析:First/Last DW Byte Enables规则与TLP Header优化实践
  • 径向基RBF神经网络的故障分类与故障诊断的Matlab程序代码
  • Git学习
  • 【Agent】大模型在线API接入基础入门
  • 想把UC3842电源从12V1A升级到12V6A?这份保姆级物料清单与改造要点请收好
  • 新手友好:零基础使用快马AI生成专利数据链接展示页
  • 告别窗口限制:WindowResizer让Windows桌面管理效率提升300%
  • Windows Subsystem for Android (WSA) 技术指南:从问题诊断到场景落地的完整实践路径