MySQL RAND() 產生 0~1 隨機浮點數,配合 ORDER BY RAND() LIMIT N 可實現隨機抽樣,但**大表全表掃描+臨時表排序效能極差**。本文系統講解 RAND() 用法、隨機查詢/更新模式、效能陷阱與工程化替代方案。
RAND() -- 每次調用返回不同值
RAND(seed) -- 固定種子,序列可重現
SELECT RAND(); -- 0.5925
SELECT RAND(20); -- 0.1811 (固定)
SELECT RAND(20); -- 0.1811 (同種子同結果)
-- 經典寫法 (小表可用,大表禁用)
SELECT * FROM t ORDER BY RAND() LIMIT 5;
執行計劃:EXPLAIN 顯示 Using temporary; Using filesort → 創建臨時表、全表掃描賦隨機值、排序、取前 N。**時間複雜度 O(N log N),大表災難級**。
| 方案 | 原理 | 適用場景 | 近似度 |
|---|---|---|---|
| 主鍵範圍 + 隨機偏移 | WHERE id >= (SELECT FLOOR(RAND() * MAX(id)) FROM t) ORDER BY id LIMIT N | 主鍵連續/較密集 | 均勻分佈 |
| 兩步法:先取隨機 ID 集合 | 應用層生成隨機 ID 列表 → WHERE id IN (...) | ID 稀疏、需精確控制 | 精確 |
| TABLESAMPLE (8.0.25+) | SELECT * FROM t TABLESAMPLE SYSTEM (10) LIMIT N | 統計抽樣、不需精確 | 頁級抽樣 |
| 偏移量法 | SELECT * FROM t LIMIT offset, N (offset = RAND()*COUNT) | 需精確 COUNT、可接受邊界偏差 | 均勻 |
-- 全表更新隨機值 (慎用,無 WHERE 會全表掃描)
UPDATE t SET rand_col = RAND();
-- 按條件批量更新
UPDATE t SET views = FLOOR(RAND() * 1000) WHERE status = 'active';
INSERT ... VALUES (RAND()), (RAND())... 批量插入隨機值同理,字段寬度需容納浮點數文本長度。
-- 方案 A: ORDER BY RAND() LIMIT 10
-- 耗時: 12.4 秒 (全表掃描 + filesort)
-- 方案 B: 主鍵範圍法
SELECT * FROM t
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM t)))
ORDER BY id LIMIT 10;
-- 耗時: 0.003 秒 (索引範圍掃描)
-- 方案 C: 兩步法 (應用層生成 10 個隨機 ID)
SELECT * FROM t WHERE id IN (1024, 5012, 99999...);
-- 耗時: 0.001 秒 (主鍵點查)
ORDER BY RAND(),代碼評審攔截、CI 靜態分析規則檢測。IN 查詢。TABLESAMPLE SYSTEM (percent)。WHERE 限制範圍,避免全表鎖升級。