測試環境需大量隨機資料。本文提供:自定義函數生成隨機字符串、預存過程批量插入、業務場景:論文引用隨機補充 及 LIMIT 隨機採樣效能優化演進。
CREATE TABLE `tables_a` (
`id` INT(10) NOT NULL DEFAULT '0',
`name` CHAR(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET GLOBAL log_bin_trust_function_creators = 1;
DROP FUNCTION IF EXISTS rand_string;
DELIMITER //
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str = CONCAT(return_str, SUBSTRING(chars_str, FLOOR(1 + RAND() * 62), 1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE test_insert(IN x INT, IN y INT, IN z INT)
BEGIN
DECLARE i INT DEFAULT x;
WHILE i < y DO
INSERT INTO tables_a VALUES (i, rand_string(z));
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
呼叫:CALL test_insert(1, 10001, 20); 插入 1 萬條 20 位隨機串。
需為每篇論文隨機添加 20 條引用關係。
INSERT INTO citation (pId1, pId2)
VALUES (
(SELECT pId FROM papers LIMIT ?, 1),
(SELECT pId FROM papers LIMIT ?, 1)
);
-- 15 萬表,插 10 萬條耗時 22 分鐘
ALTER TABLE papers ADD COLUMN temp INT AUTO_INCREMENT PRIMARY KEY;
-- 應用層生成 20 個不重複隨機數 0~N
INSERT INTO citation (pId1, pId2)
VALUES (
(SELECT pId FROM papers WHERE temp = ?),
(SELECT pId FROM papers WHERE temp = ?)
);
-- 10 萬條耗時 38 秒
SELECT * FROM t ORDER BY RAND() LIMIT 5 全表掃描 + 檔案排序,15 萬表耗 8 秒+。
SELECT * FROM t AS t1
JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM t)) AS id) AS t2
WHERE t1.id >= t2.id ORDER BY t1.id ASC LIMIT 5;
-- 產生連續 5 行,非真正隨機
SELECT * FROM t
WHERE id >= (SELECT FLOOR(MAX(id) * RAND()) FROM t)
ORDER BY id LIMIT 1;
-- 0.5 秒
SELECT * FROM t
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM t)))
ORDER BY id LIMIT 1;
-- 0.01 秒
SELECT * FROM t
WHERE id >= (
SELECT FLOOR(
RAND() * ((SELECT MAX(id) FROM t) - (SELECT MIN(id) FROM t))
+ (SELECT MIN(id) FROM t)
)
)
ORDER BY id LIMIT 1;
SELECT * FROM t AS t1
JOIN (
SELECT ROUND(
RAND() * ((SELECT MAX(id) FROM t) - (SELECT MIN(id) FROM t))
+ (SELECT MIN(id) FROM t)
) AS id
) AS t2
WHERE t1.id >= t2.id ORDER BY t1.id LIMIT 1;
隨機採樣核心:**避免 ORDER BY RAND(),利用主鍵範圍 + RAND() 計算邊界,JOIN 形式最穩定**。