-- ============================================ -- 优化的压力测试数据生成脚本 -- 使用批量生成 + 临时表,避免循环中的随机查询 -- ============================================ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ============================================ -- 1. 批量生成用户数据 -- ============================================ DROP PROCEDURE IF EXISTS generate_users_batch; DELIMITER $$ CREATE PROCEDURE generate_users_batch(IN batch_size INT) BEGIN DECLARE batch_limit INT DEFAULT 1000; DECLARE batches INT; DECLARE current_batch INT DEFAULT 0; DECLARE batch_start INT; DECLARE batch_end INT; DECLARE current_limit INT; SET batches = CEIL(batch_size / batch_limit); WHILE current_batch < batches DO SET batch_start = current_batch * batch_limit + 1; SET batch_end = LEAST((current_batch + 1) * batch_limit, batch_size); SET current_limit = batch_end - batch_start + 1; -- 使用 INSERT ... SELECT 批量生成 INSERT INTO users (phone, nickname, realname_status, risk_status, credit_score, status, created_at) SELECT CONCAT('138', LPAD(seq, 8, '0')) as phone, CONCAT('测试用户', seq) as nickname, CASE WHEN seq % 10 = 0 THEN 'unverified' ELSE 'verified' END as realname_status, CASE WHEN seq % 100 = 0 THEN 'frozen' ELSE 'normal' END as risk_status, 80 + (seq % 20) as credit_score, 'active' as status, DATE_SUB(NOW(), INTERVAL (seq % 365) DAY) as created_at FROM ( SELECT @row := @row + 1 AS seq FROM (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3, (SELECT @row := batch_start - 1) r LIMIT current_limit ) seqs ON DUPLICATE KEY UPDATE id=id; SET current_batch = current_batch + 1; COMMIT; END WHILE; -- 批量生成实名记录(为已实名用户) INSERT INTO user_realname (user_id, provider, status, masked_name, masked_id_no, verified_at) SELECT u.id, 'mock', 'success', CONCAT('张*', CHAR(65 + (u.id % 26))), CONCAT('3301**********', LPAD(u.id % 10000, 4, '0')), DATE_SUB(NOW(), INTERVAL (u.id % 300) DAY) FROM users u WHERE u.realname_status = 'verified' AND NOT EXISTS (SELECT 1 FROM user_realname WHERE user_id = u.id); -- 批量生成钱包账户 INSERT INTO wallet_accounts (user_id, available_balance, frozen_balance, status) SELECT u.id, (u.id % 10) * 100.00, (u.id % 5) * 50.00, 'active' FROM users u WHERE NOT EXISTS (SELECT 1 FROM wallet_accounts WHERE user_id = u.id); COMMIT; END$$ DELIMITER ; -- ============================================ -- 2. 批量生成游戏账号和商品 -- ============================================ DROP PROCEDURE IF EXISTS generate_listings_batch; DELIMITER $$ CREATE PROCEDURE generate_listings_batch(IN batch_size INT) BEGIN DECLARE batch_limit INT DEFAULT 1000; DECLARE batches INT; DECLARE current_batch INT DEFAULT 0; DECLARE verified_user_count INT DEFAULT 0; -- 创建临时表存储已实名用户ID DROP TEMPORARY TABLE IF EXISTS tmp_verified_users; CREATE TEMPORARY TABLE tmp_verified_users ( id BIGINT PRIMARY KEY, row_num INT ); INSERT INTO tmp_verified_users (id, row_num) SELECT id, (@rn := @rn + 1) as row_num FROM users, (SELECT @rn := 0) init WHERE realname_status = 'verified' ORDER BY id; SELECT COUNT(*) INTO verified_user_count FROM tmp_verified_users; SET batches = CEIL(batch_size / batch_limit); WHILE current_batch < batches DO -- 批量生成游戏账号 INSERT INTO game_accounts ( owner_id, game_name, server_region, login_platform, title, description, rank_level, haf_coin_amount, status ) SELECT u.id as owner_id, 'delta_force', CASE (seq % 4) WHEN 0 THEN '亚服' WHEN 1 THEN '美服' WHEN 2 THEN '欧服' ELSE '国服' END, CASE (seq % 3) WHEN 0 THEN 'Steam' WHEN 1 THEN 'Epic' ELSE 'WeGame' END, CONCAT('账号', seq, ' 高分段'), CONCAT('这是一个测试账号,编号', seq), CASE (seq % 5) WHEN 0 THEN '青铜' WHEN 1 THEN '白银' WHEN 2 THEN '黄金' WHEN 3 THEN '铂金' ELSE '钻石' END, (seq % 100) * 10000, 'published' FROM ( SELECT @row2 := @row2 + 1 AS seq FROM (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3, (SELECT @row2 := current_batch * batch_limit) r LIMIT batch_limit ) seqs INNER JOIN tmp_verified_users u ON u.row_num = (seq % verified_user_count) + 1 WHERE seq <= batch_size; -- 批量生成租号商品 INSERT INTO rental_listings ( listing_no, account_id, owner_id, price, deposit_amount, in_transaction, status, review_status, published_at ) SELECT CONCAT( DATE_FORMAT(DATE_SUB(NOW(), INTERVAL (ga.id % 90) DAY), '%Y%m%d'), LPAD(FLOOR((ga.id - 1) / 90) + 1, 4, '0') ) as listing_no, ga.id as account_id, ga.owner_id, 5.00 + ((ga.id % 20) * 0.5) as price, 100.00 + ((ga.id % 10) * 50.00) as deposit_amount, CASE WHEN ga.id % 10 = 0 THEN 1 ELSE 0 END as in_transaction, CASE WHEN ga.id % 20 = 0 THEN 'offline' WHEN ga.id % 15 = 0 THEN 'draft' ELSE 'published' END as status, CASE WHEN ga.id % 15 = 0 THEN 'pending' WHEN ga.id % 30 = 0 THEN 'rejected' ELSE 'approved' END as review_status, DATE_SUB(NOW(), INTERVAL (ga.id % 90) DAY) as published_at FROM game_accounts ga WHERE ga.id > (SELECT COALESCE(MAX(account_id), 0) FROM rental_listings) LIMIT batch_limit; SET current_batch = current_batch + 1; COMMIT; END WHILE; INSERT INTO listing_no_sequences (biz_date, next_seq) SELECT LEFT(listing_no, 8), MAX(CAST(SUBSTRING(listing_no, 9) AS UNSIGNED)) FROM rental_listings GROUP BY LEFT(listing_no, 8) ON DUPLICATE KEY UPDATE next_seq = GREATEST(next_seq, VALUES(next_seq)); COMMIT; DROP TEMPORARY TABLE IF EXISTS tmp_verified_users; END$$ DELIMITER ; -- ============================================ -- 3. 批量生成订单数据(优化版) -- ============================================ DROP PROCEDURE IF EXISTS generate_orders_batch; DELIMITER $$ CREATE PROCEDURE generate_orders_batch(IN batch_size INT) BEGIN DECLARE batch_limit INT DEFAULT 1000; DECLARE batches INT; DECLARE current_batch INT DEFAULT 0; DECLARE available_listing_count INT DEFAULT 0; DECLARE verified_user_count INT DEFAULT 0; -- 创建临时表:可用商品 DROP TEMPORARY TABLE IF EXISTS tmp_available_listings; CREATE TEMPORARY TABLE tmp_available_listings ( id BIGINT PRIMARY KEY, account_id BIGINT, owner_id BIGINT, price DECIMAL(12,2), deposit_amount DECIMAL(12,2), row_num INT ); INSERT INTO tmp_available_listings (id, account_id, owner_id, price, deposit_amount, row_num) SELECT id, account_id, owner_id, price, deposit_amount, (@rn := @rn + 1) FROM rental_listings, (SELECT @rn := 0) init WHERE status IN ('published', 'active') AND review_status = 'approved' ORDER BY id; SELECT COUNT(*) INTO available_listing_count FROM tmp_available_listings; -- 创建临时表:已实名用户 DROP TEMPORARY TABLE IF EXISTS tmp_verified_users; CREATE TEMPORARY TABLE tmp_verified_users ( id BIGINT PRIMARY KEY, row_num INT ); INSERT INTO tmp_verified_users (id, row_num) SELECT id, (@rn2 := @rn2 + 1) FROM users, (SELECT @rn2 := 0) init WHERE realname_status = 'verified' ORDER BY id; SELECT COUNT(*) INTO verified_user_count FROM tmp_verified_users; SET batches = CEIL(batch_size / batch_limit); WHILE current_batch < batches DO INSERT INTO rental_orders ( order_no, listing_id, account_id, owner_id, renter_id, estimated_duration_hours, rent_amount, owner_rent_amount, deposit_amount, platform_fee, status, handoff_status, settlement_status, rented_at, created_at ) SELECT CONCAT('ORD', DATE_FORMAT(NOW(), '%Y%m%d'), LPAD(seq, 8, '0')) as order_no, l.id as listing_id, l.account_id, l.owner_id, r.id as renter_id, 24 as estimated_duration_hours, l.price * 24 as rent_amount, l.price * 24 * 0.95 as owner_rent_amount, l.deposit_amount, l.price * 24 * 0.05 as platform_fee, CASE (seq % 10) WHEN 0 THEN 'pending_payment' WHEN 1 THEN 'cancelled' WHEN 2 THEN 'closed' ELSE 'completed' END as status, CASE (seq % 10) WHEN 0 THEN 'none' WHEN 1 THEN 'none' WHEN 2 THEN 'owner_delivered' ELSE 'owner_received' END as handoff_status, CASE (seq % 10) WHEN 0 THEN 'unsettled' WHEN 1 THEN 'unsettled' ELSE 'settled' END as settlement_status, DATE_SUB(NOW(), INTERVAL (seq % 60) DAY) as rented_at, DATE_SUB(NOW(), INTERVAL (seq % 60) DAY) as created_at FROM ( SELECT @row3 := @row3 + 1 AS seq FROM (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3, (SELECT @row3 := current_batch * batch_limit) r LIMIT batch_limit ) seqs INNER JOIN tmp_available_listings l ON l.row_num = (seq % available_listing_count) + 1 INNER JOIN tmp_verified_users r ON r.row_num = (seq % verified_user_count) + 1 WHERE seq <= batch_size AND r.id != l.owner_id LIMIT batch_limit; SET current_batch = current_batch + 1; COMMIT; END WHILE; DROP TEMPORARY TABLE IF EXISTS tmp_available_listings; DROP TEMPORARY TABLE IF EXISTS tmp_verified_users; END$$ DELIMITER ; -- ============================================ -- 4. 批量生成钱包流水 -- ============================================ DROP PROCEDURE IF EXISTS generate_wallet_ledger_batch; DELIMITER $$ CREATE PROCEDURE generate_wallet_ledger_batch(IN batch_size INT) BEGIN DECLARE batch_limit INT DEFAULT 1000; DECLARE batches INT; DECLARE current_batch INT DEFAULT 0; DECLARE user_count INT DEFAULT 0; DECLARE order_count INT DEFAULT 0; -- 创建临时表:用户列表 DROP TEMPORARY TABLE IF EXISTS tmp_users; CREATE TEMPORARY TABLE tmp_users ( id BIGINT PRIMARY KEY, row_num INT ); INSERT INTO tmp_users (id, row_num) SELECT id, (@rn := @rn + 1) FROM users, (SELECT @rn := 0) init ORDER BY id; SELECT COUNT(*) INTO user_count FROM tmp_users; -- 创建临时表:订单列表 DROP TEMPORARY TABLE IF EXISTS tmp_orders; CREATE TEMPORARY TABLE tmp_orders ( id BIGINT PRIMARY KEY, row_num INT ); INSERT INTO tmp_orders (id, row_num) SELECT id, (@rn2 := @rn2 + 1) FROM rental_orders, (SELECT @rn2 := 0) init ORDER BY id; SELECT COUNT(*) INTO order_count FROM tmp_orders; SET batches = CEIL(batch_size / batch_limit); WHILE current_batch < batches DO INSERT INTO wallet_ledger ( ledger_no, user_id, order_id, direction, amount, balance_after, balance_type, biz_type, biz_no, remark, created_at ) SELECT CONCAT('LDG', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s'), LPAD(seq, 6, '0')) as ledger_no, u.id as user_id, IF(seq % 2 = 0, o.id, NULL) as order_id, CASE WHEN seq % 2 = 0 THEN 'in' ELSE 'out' END as direction, (seq % 500) + (seq * 0.01) as amount, 1000.00 + (seq % 1000) as balance_after, CASE WHEN seq % 5 = 0 THEN 'frozen' ELSE 'available' END as balance_type, CASE (seq % 6) WHEN 0 THEN 'rent_payment' WHEN 1 THEN 'deposit_freeze' WHEN 2 THEN 'settlement' WHEN 3 THEN 'refund' WHEN 4 THEN 'recharge' ELSE 'withdraw' END as biz_type, CONCAT('BIZ', LPAD(seq, 10, '0')) as biz_no, CONCAT('测试流水', seq) as remark, DATE_SUB(NOW(), INTERVAL (seq % 180) DAY) as created_at FROM ( SELECT @row4 := @row4 + 1 AS seq FROM (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3, (SELECT @row4 := current_batch * batch_limit) r LIMIT batch_limit ) seqs INNER JOIN tmp_users u ON u.row_num = (seq % user_count) + 1 LEFT JOIN tmp_orders o ON o.row_num = (seq % order_count) + 1 WHERE seq <= batch_size LIMIT batch_limit; SET current_batch = current_batch + 1; COMMIT; END WHILE; DROP TEMPORARY TABLE IF EXISTS tmp_users; DROP TEMPORARY TABLE IF EXISTS tmp_orders; END$$ DELIMITER ; -- ============================================ -- 5. 批量生成聊天会话和消息 -- ============================================ DROP PROCEDURE IF EXISTS generate_chat_data_batch; DELIMITER $$ CREATE PROCEDURE generate_chat_data_batch(IN message_count INT) BEGIN DECLARE batch_limit INT DEFAULT 1000; DECLARE batches INT; DECLARE current_batch INT DEFAULT 0; DECLARE conversation_count INT DEFAULT 0; DECLARE user_count INT DEFAULT 0; -- 先生成聊天会话(基于订单) INSERT INTO chat_conversations (order_id, type, title, status, last_message_at) SELECT ro.id, 'order_group', CONCAT('订单', ro.order_no, '群聊'), 'active', ro.created_at FROM rental_orders ro WHERE NOT EXISTS (SELECT 1 FROM chat_conversations WHERE order_id = ro.id) LIMIT 1000 ON DUPLICATE KEY UPDATE order_id=order_id; DROP TEMPORARY TABLE IF EXISTS tmp_conversations; CREATE TEMPORARY TABLE tmp_conversations ( id BIGINT PRIMARY KEY, row_num INT ); INSERT INTO tmp_conversations (id, row_num) SELECT id, (@rn := @rn + 1) FROM chat_conversations, (SELECT @rn := 0) init ORDER BY id; SELECT COUNT(*) INTO conversation_count FROM tmp_conversations; DROP TEMPORARY TABLE IF EXISTS tmp_users; CREATE TEMPORARY TABLE tmp_users ( id BIGINT PRIMARY KEY, row_num INT ); INSERT INTO tmp_users (id, row_num) SELECT id, (@rn2 := @rn2 + 1) FROM users, (SELECT @rn2 := 0) init ORDER BY id; SELECT COUNT(*) INTO user_count FROM tmp_users; SET batches = CEIL(message_count / batch_limit); WHILE current_batch < batches DO INSERT INTO chat_messages ( conversation_id, sender_type, sender_id, sender_role, content_type, content, created_at ) SELECT c.id as conversation_id, 'user' as sender_type, u.id as sender_id, CASE WHEN seq % 2 = 0 THEN 'owner' ELSE 'renter' END as sender_role, 'text' as content_type, CONCAT('这是测试消息', seq, ',内容随机生成用于压力测试') as content, DATE_SUB(NOW(), INTERVAL (seq % 30) DAY) as created_at FROM ( SELECT @row5 := @row5 + 1 AS seq FROM (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2, (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3, (SELECT @row5 := current_batch * batch_limit) r LIMIT batch_limit ) seqs INNER JOIN tmp_conversations c ON c.row_num = (seq % conversation_count) + 1 INNER JOIN tmp_users u ON u.row_num = (seq % user_count) + 1 WHERE seq <= message_count LIMIT batch_limit; SET current_batch = current_batch + 1; COMMIT; END WHILE; DROP TEMPORARY TABLE IF EXISTS tmp_conversations; DROP TEMPORARY TABLE IF EXISTS tmp_users; END$$ DELIMITER ; -- ============================================ -- 本文件只创建存储过程,不直接生成数据。 -- 请使用 scripts/stress_test.sh data 按参数生成 -- ============================================ SET FOREIGN_KEY_CHECKS = 1;