SELECT * FROM news ORDER BY RAND() LIMIT 10 在幾十萬資料時會全表排序,耗時秒級甚至分鐘級。
SELECT * FROM `news`
WHERE id >= (
SELECT FLOOR(RAND() * (SELECT MAX(id) FROM `news`))
)
LIMIT 10;
原理:在 [1, MAX(id)] 取隨機數,查第一筆 ≥ 該值的記錄。
**缺點**:ID 有空洞時,分布偏向空洞後的記錄。
SELECT * FROM `news` AS t1
JOIN (
SELECT ROUND(
RAND() * ((SELECT MAX(id) FROM `news`) - (SELECT MIN(id) FROM `news`))
+ (SELECT MIN(id) FROM `news`)
) AS id
) AS t2 ON t1.id >= t2.id
LIMIT 10;
原理:在 [MIN(id), MAX(id)] 區間均勻取隨機起點,再向後取 10 筆。
| 寫法 | 耗時 | 說明 |
|---|---|---|
ORDER BY RAND() LIMIT 10 | ~2.3 秒 | 全表排序 |
| 方案一(子查詢) | ~0.003 秒 | 索引範圍掃描 |
| 方案二(JOIN) | ~0.004 秒 | 兩次標量子查詢 + 索引掃描 |
SELECT * FROM `news`
WHERE RAND() < 10 / (SELECT COUNT(*) FROM `news`)
LIMIT 10;
每行獨立以概率 n/總行數 被選中,**統計學完全均勻**,但需全表掃描計算 RAND(),適合中等表(< 10 萬行)。
rand_sort 欄位定期更新,查詢時 ORDER BY rand_sort LIMIT n**核心口訣:善用索引範圍掃描替代全表排序,隨機只在「起點」產生。**