ORDER BY RAND() 極慢?ORDER BY 中使用 RAND()
-- 核心思想:隨機一個 ID 範圍內的值,向後取第一條
SELECT * FROM `table`
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM `table`)))
ORDER BY id LIMIT 1;
| 方案 | SQL | 耗時 | 備註 |
|---|---|---|---|
| 原始 RAND | ORDER BY RAND() LIMIT 1 | 8.0 s+ | 全表掃描+排序 |
| 子查詢 MAX*RAND | WHERE id >= (SELECT FLOOR(MAX(id)*RAND())...) | 0.5 s | 仍有子查詢開銷 |
| 優化子查詢 | WHERE id >= (SELECT FLOOR(RAND()*(MAX-MIN)+MIN)...) | 0.01 s | 含 MIN 修正空洞 |
| JOIN 寫法 | JOIN (SELECT ROUND(RAND()*(MAX-MIN)+MIN) AS id) t2 ON t1.id>=t2.id | 0.0015 s | 最快,JOIN 優於 WHERE 子查詢 |
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;
方案:循環執行 N 次單行查詢,或應用層收集 ID 後 WHERE id IN (...)。
-- PHP 示例
$ids = [];
for ($i=0; $i<5; $i++) {
$id = $pdo->query("SELECT id FROM t ORDER BY RAND() LIMIT 1")->fetchColumn();
$ids[] = $id;
}
$stmt = $pdo->prepare("SELECT * FROM t WHERE id IN (" . implode(',', array_fill(0,5,'?')) . ")");
$stmt->execute($ids);