經典寫法 SELECT * FROM tbl ORDER BY RAND() LIMIT 5 在 15 萬筆資料表中耗時 8 秒以上。官方文檔明確警告:RAND() 在 ORDER BY 中會被多次評估,導致全表掃描與臨時表排序,效能極差。
SELECT * FROM `table`
WHERE id >= (SELECT FLOOR(MAX(id) * RAND()) FROM `table`)
ORDER BY id LIMIT 1;
缺點:ID 不連續時易查到前段資料,需補上 MIN(id) 修正。
SELECT * FROM `table` AS t1
JOIN (
SELECT ROUND(RAND() * (
(SELECT MAX(id) FROM `table`) - (SELECT MIN(id) FROM `table`)
) + (SELECT MIN(id) FROM `table`)) AS id
) AS t2 ON t1.id >= t2.id
ORDER BY t1.id LIMIT 1;
優勢:利用索引快速定位,避免全表排序。
若需 5 筆不連續資料,執行 5 次方案二(或用應用層去重),總耗時 ~0.05 秒,遠優於原生 RAND()。
| 方案 | 總耗時 | 平均單次 |
|---|---|---|
| WHERE 子查詢 | 0.147 秒 | 0.015 秒 |
| JOIN 衍生表 | 0.015 秒 | 0.0015 秒 |
range 或 ref 存取。MIN(id) 修正偏移量。COUNT(*) 再 LIMIT offset, 1)。SRANDMEMBER 卸載 DB 壓力。