5 萬行表,ORDER BY RAND() LIMIT 10 耗時 5 秒+。業務需高頻隨機推薦,完全不可接受。
SELECT * FROM `table` ORDER BY RAND() LIMIT 10;
-- 5 秒+,全表掃描 + 臨時表 + filesort
SELECT * FROM `table` AS t1
JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 10;
-- 0.01 秒,但返回連續 10 行,非真隨機
-- 未優化
SELECT * FROM `table`
WHERE id >= (SELECT FLOOR(MAX(id) * RAND()) FROM `table`)
ORDER BY id LIMIT 1;
-- 0.5 秒
-- 優化:RAND() 移出聚合
SELECT * FROM `table`
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM `table`)))
ORDER BY id LIMIT 1;
-- 0.01 秒
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;
-- 解決 ID 從 10000 起導致前段資料被過度查詢
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;
-- 10 次總耗時 0.015 秒,單次 0.0015 秒
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 10;
-- 單次查詢取 10 行(連續段),業務可接受「近似隨機」
-- 耗時 0.0003 秒,比原始 5 秒快 16000 倍
| 代數 | 方案 | 單次耗時 | 10 次/10 行耗時 | 隨機度 | 備註 |
|---|---|---|---|---|---|
| 1 | ORDER BY RAND() | ~5000 ms | ~50000 ms | 真隨機 | 不可用 |
| 2 | MAX JOIN 連續 | 10 ms | 100 ms | 連續段 | 需去重 |
| 3 | WHERE 子查詢 | 500 ms → 10 ms | 5000 → 100 ms | 單行真隨機 | 優化後可用 |
| 4 | MIN/MAX 修正 | 10 ms | 100 ms | 單行真隨機 | 通用修正 |
| 5 | JOIN 最終版 | 1.5 ms | 15 ms | 單行真隨機 | 單行首選 |
| 6 | JOIN 批量 LIMIT 10 | 0.3 ms | 0.3 ms | 近似隨機(連續段) | 批量首選 |
id 為主鍵/唯一索引,且型別為整數(BIGINT/INT)。seq_id 影子欄位(觸發器維護 1..N 連續),隨機查 seq_id 再 JOIN 回主表。CRC32() 或 CONV(SUBSTRING(MD5(),1,16),16,10) 映射為數值,建立函數索引(MySQL 8.0+)或影子欄位。SRANDMEMBER / ZRANDMEMBER 緩存熱點 ID 集合,降級走 MySQL。ORDER BY RAND() 殘留。
-- Bernoulli 採樣(每行獨立概率)
SELECT * FROM `table` TABLESAMPLE BERNOULLI (0.1) LIMIT 10;
-- SYSTEM 採樣(頁面級,更快但較粗糙)
SELECT * FROM `table` TABLESAMPLE SYSTEM (10) LIMIT 10;
無需索引、無需主鍵整數、真隨機、極快。但 8.0.25+ 才支援,且為近似行數。