15 萬筆資料表,`SELECT * FROM t ORDER BY RAND() LIMIT 5` 耗時 8 秒+。官方文檔明確警告:`RAND()` 在 `ORDER BY` 中會被多次評估,導致效能崩潰。
| 版本 | SQL 寫法 | 耗時 | 缺點 |
|---|---|---|---|
| v1 | ORDER BY RAND() LIMIT 5 | 8 秒 | 全表掃描+檔案排序 |
| v2 | JOIN (SELECT ROUND(RAND()*MAX(id)) AS id) ... | 0.01 秒 | 產生連續 5 筆(非真隨機) |
| v3 | WHERE id >= (SELECT FLOOR(MAX(id)*RAND())) ... LIMIT 1 | 0.5 秒 | 子查詢執行多次 |
| v4 | WHERE id >= (SELECT FLOOR(RAND()*(MAX-MIN)+MIN)) ... LIMIT 1 | 0.01 秒 | 單次隨機,但需執行 5 次取 5 筆 |
| v5 (最佳) | JOIN (SELECT ROUND(RAND()*(MAX-MIN)+MIN) AS id) ... LIMIT 1 | 0.0015 秒 | 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;
$ids = [];
for ($i=0; $i<5; $i++) {
$sql = "上面的最佳SQL";
$row = $pdo->query($sql)->fetch();
if ($row && !in_array($row['id'], $ids)) {
$ids[] = $row['id'];
$results[] = $row;
}
}
總耗時約 0.007 秒,較原 8 秒提升 1000 倍。