在 MySQL 中隨機抽取數據是常見需求。本文對比兩種方案的原理、性能與適用版本,助你選擇最優策略。
SELECT * FROM table_name ORDER BY RAND() LIMIT 5;
原理:為每行生成隨機數排序後取前 N 行。MySQL 手冊說明:RAND() 返回 0-1 浮點數,指定種子 RAND(N) 可重現序列。3.23+ 版本支持在 ORDER BY 中使用。
實測缺陷:8 千行表單次查詢耗時 0.08 秒。隨數據量增長,全表掃描+文件排序導致性能急劇下降,不推薦用於生產環境大表。
SELECT *
FROM table_name AS r1
JOIN (
SELECT ROUND(RAND() * (SELECT MAX(id) FROM table_name)) AS id
) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 5;
原理:利用主鍵 ID 連續性,隨機生成一個 ID 閾值,向後掃描取滿 LIMIT 行。避免全表排序,僅需索引範圍掃描。
實測優勢:同等數據下耗時 0.02 秒,性能提升 4 倍。
限制:僅 MySQL 4.1+ 支持子查詢;要求主鍵為自增整數且無大量空洞;若 ID 分佈不均可能導致抽樣偏差。
| 場景 | 推薦方案 |
|---|---|
| 小表(<1 萬行) | ORDER BY RAND() 簡潔易維護 |
| 大表、MySQL 4.1+、主鍵連續 | JOIN 子查詢法 |
| 大表、舊版本或主鍵非連續 | 應用層兩步法: 1. SELECT COUNT(*) 得總行數2. SELECT * FROM table LIMIT $offset, 1 (PHP: mt_rand(0, $count-1)) |
| 需嚴格均勻隨機樣本 | Berkeley 算法 / 桶式採樣 / TABLESAMPLE (8.0+) |