`SELECT * FROM t ORDER BY RAND() LIMIT N` 是 MySQL 最經典的反模式:在百萬級表上耗時秒級甚至分鐘。本文深度剖析其性能瓶頸,並提供經過實戰驗證的高性能隨機查詢方案,助你實現毫秒級隨機採樣。
實測數據:15 萬行表查 5 條,`ORDER BY RAND()` 耗時 8 秒+。
利用主鍵 `id` 連續/近似連續特性,將「隨機排序」轉化為「隨機定位 + 索引查找」。
SELECT * FROM `table` WHERE id >= (SELECT FLOOR(MAX(id) * RAND()) FROM `table`) ORDER BY id LIMIT 1;
⚠️ 缺陷:易產生連續 5 條記錄;若 id 有空洞,分佈不均。
SELECT * FROM `table` AS t1 JOIN ( SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id ) AS t2 ON t1.id >= t2.id ORDER BY t1.id LIMIT 5;
⚠️ 同樣產生連續行;需循環執行 5 次獲取不連續結果。
SELECT * FROM `table`
WHERE id >= (
SELECT FLOOR(RAND() * ((SELECT MAX(id) FROM `table`) - (SELECT MIN(id) FROM `table`)))
+ (SELECT MIN(id) FROM `table`)
)
ORDER BY id LIMIT 1;
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;
| 方案 | 總耗時 | 平均耗時 | 評價 |
|---|---|---|---|
| ORDER BY RAND() LIMIT 1 | 80+ 秒 | 8 秒 | ❌ 生產禁用 |
| 子查詢 + MAX*RAND | 5 秒 | 0.5 秒 | ⚠️ 有偏差 |
| 子查詢 + MIN/MAX 修正 | 0.1 秒 | 0.01 秒 | ✅ 可用 |
| JOIN + MIN/MAX 修正 | 0.15 秒 | 0.015 秒 | 🏆 最優 |
單條查詢循環 N 次(應用層去重)最簡單;純 SQL 方案:
-- 方案:生成 N 個隨機主鍵,再 IN 查詢(需應用層生成隨機 ID 列表) SELECT * FROM `table` WHERE id IN (id1, id2, ..., idN);
MySQL 高效隨機查詢的本質是用索引查找替換全表排序。掌握「主鍵範圍 + JOIN 衍生表 + MIN/MAX 修正」這一核心模式,配合應用層隨機 ID 生成策略,可將隨機採樣延遲從秒級壓縮至毫秒級,滿足推薦系統、廣告輪播、A/B 測試等高併發業務的嚴苛 SLA 要求。