ORDER BY RAND() 會觸發 Using filesort 且導致全表掃描(type=ALL),索引完全失效。百萬筆資料下執行時間可達分鐘級,生產環境**嚴禁使用**。
| 方案 | SQL 核心邏輯 | 單筆耗時 | 百筆耗時 | 隨機性 | 評價 |
|---|---|---|---|---|---|
| 1. ORDER BY RAND() | SELECT * FROM users ORDER BY RAND() LIMIT 1 | 極慢(未完成) | — | 高 | ❌ 禁用 |
| 2. JOIN 子查詢 | SELECT * FROM users t1 JOIN (SELECT ROUND(RAND()*(MAX-MIN)+MIN) AS id FROM users) t2 ON t1.userId >= t2.id ORDER BY t1.userId LIMIT 1 | 0.031s | 0.048s | 單筆佳,多筆**非隨機** | ⚠️ 單筆可用 |
| 3. WHERE 隨機範圍(推薦) | SELECT * FROM users WHERE userId >= (SELECT MIN(userId) FROM users) + RAND()*(MAX-MIN) LIMIT 1 | 0.039s | 0.063s (1萬筆) | ✅ 高 | ✅ 最佳 |
| 4. 應用層產生隨機 ID | PHP rand($min, $max) → WHERE id >= $rand LIMIT 1 | 極快 | 不適用多筆 | 高 | ✅ 單筆最快 |
-- 取得範圍
SELECT MIN(id), MAX(id) FROM table;
-- 方案 A:單一隨機點(缺點:尾部資料機率低)
SELECT * FROM table WHERE id > $rand LIMIT $n;
-- 方案 B:多點 IN 查詢(隨機性強,效能稍遜)
SELECT * FROM table WHERE id IN ($rand1, $rand2, ...);
-- 1. 取得總數
SELECT COUNT(*) FROM table WHERE group_id = 1; -- 假設 10000 筆
-- 2. 應用層產生 N 個隨機 offset
-- 3. 迴圈執行(可用 UNION ALL 或 Prepared Statement 批次化)
SELECT * FROM table WHERE group_id = 1 LIMIT $offset, 1;
SELECT * FROM users TABLESAMPLE SYSTEM (10) LIMIT 100; -- 10% 區塊採樣
結論:百萬級資料隨機查詢,**方案 3(WHERE 隨機範圍)兼顧效能與隨機性**;非連續 ID 採用「總數 + 多點 OFFSET」配合批次查詢;嚴禁
ORDER BY RAND()。