在 MySQL 中,最直觀的隨機查詢寫法是 SELECT * FROM tablename ORDER BY RAND() LIMIT 1。這語法簡單,但在資料量超過 30 萬筆時,效能會急劇下降。原因在於 MySQL 必須為所有資料列產生隨機數、排序、再取第一筆,這過程涉及全表掃描與臨時表排序,CPU 与 I/O 開銷極大。
PHP 官方手冊針對擁有 AUTO_INCREMENT 主鍵的表,提供了一種更高效的做法:
SELECT MIN(id), MAX(id) FROM tablename;$id = rand($min, $max);SELECT * FROM tablename WHERE id >= '$id' LIMIT 1;此法僅需兩次極快的索引查詢,避免了全表排序,效能提升顯著。
WHERE id >= $id ORDER BY id LIMIT 1 配合應用層重試。WHERE id IN (...) 批次查詢。若不想引入應用層邏輯,可用子查詢在單條 SQL 中完成:
SELECT * FROM `news`
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM `news`)))
LIMIT 10;
或採用 JOIN 方式(適合有 MIN/MAX 索引的表):
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;
這兩種寫法在幾十萬資料量下表現良好,避免了 ORDER BY RAND() 的全表排序開銷。
| 場景 | 推薦做法 |
|---|---|
| 小表(< 1 萬筆) | ORDER BY RAND() LIMIT n 簡單可用 |
| 大表、單筆隨機、有自增主鍵 | 應用層 MIN/MAX + rand() + WHERE id >= ? |
| 大表、多筆隨機、純 SQL | 子查詢或 JOIN 方式取隨機起點 |
| 極高均勻度要求 | 預先建立隨機排序欄位或使用 TABLESAMPLE(MySQL 8.0+) |
核心原則:避免全表排序,善用索引與應用層協作。