常見隨機抽取寫法:
SELECT * FROM t ORDER BY RAND() LIMIT 1;
官方文檔警告:ORDER BY 子句中使用 RAND() 會導致該列被多次掃描評估,效率極低。實測 15 萬行表查 5 行耗時 8 秒+。
核心思路:先在主鍵 ID 範圍內隨機生成一個值,再查找大於等於該值的第一行。
SELECT t1.*
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 ASC LIMIT 1;
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;
若表主鍵不從 1 開始或有刪除空洞,直接用 MAX(id) * RAND() 會導致前段數據被查中概率極高。加上 MIN(id) 偏移量可保證均勻分布。
IN 查詢。| 方法 | 適用場景 | 效能 | 備註 |
|---|---|---|---|
| ORDER BY RAND() | 小表(<1萬行) | 極差 | 全表掃描+文件排序 |
| JOIN 隨機 ID | 大表、有自增主鍵 | 極佳 | 推薦生產環境 |
| 應用層隨機 ID | 極大表、分庫分表 | 極佳 | 應用生成隨機 ID,SQL 直接點查 |
| TABLESAMPLE (8.0+) | 統計採樣 | 好 | 伯努利/系統採樣,非精確隨機行 |