SELECT * FROM `table`; -- 撈全表
$list = $stmt->fetchAll();
$random = $list[mt_rand(0, count($list)-1)]; // mt_rand 比 rand 快 4 倍
配合 Redis/Memcached 快取結果集,適合 < 1 萬行靜態/準靜態表。
-- 經典寫法 (全表掃描 + filesort,極慢)
SELECT * FROM `table` ORDER BY RAND() LIMIT 1;
-- 優化:利用主鍵連續性 (假設 ID 無大量空洞)
SELECT * FROM `table`
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM `table`)))
ORDER BY id LIMIT 1;
**缺陷**:ID 不連續 (刪除/間隙) 導致分布不均、可能查無結果需重試。
| 類型 | 關鍵字 | 語意 | 結果集 |
|---|---|---|---|
| 交叉連接 | CROSS JOIN / JOIN / , | 笛卡爾積 | M × N 行 |
| 內連接 | INNER JOIN | 滿足 ON 條件的匹配行 | 交集 |
| 左外連接 | LEFT [OUTER] JOIN | 左表全保留 + 右表匹配 | 左表行數 ≥ 結果行數 |
| 右外連接 | RIGHT [OUTER] JOIN | 右表全保留 + 左表匹配 | 右表行數 ≥ 結果行數 |
SELECT u.id, u.name
FROM user u
LEFT JOIN user_action a ON u.id = a.user_id
WHERE a.user_id IS NULL; -- a.user_id 必須 NOT NULL
SELECT o.*, u.name
FROM orders o JOIN users u ON o.user_id = u.id
WHERE o.status = 'paid'
ORDER BY RAND() LIMIT 10;
-- 慢查詢:產生臨時表 + filesort,隨資料增長指數級惡化
SELECT id FROM orders
WHERE status = 'paid'
AND id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM orders WHERE status='paid')))
ORDER BY id LIMIT 10;
SELECT o.*, u.name
FROM orders o JOIN users u ON o.user_id = u.id
WHERE o.id IN (?, ?, ...); -- 參數化 IN 列表
SELECT o.*, u.name
FROM (
SELECT id FROM orders
WHERE status = 'paid'
AND id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM orders WHERE status='paid')))
ORDER BY id LIMIT 10
) rand_ids
JOIN orders o ON o.id = rand_ids.id
JOIN users u ON o.user_id = u.id;
**關鍵索引**:orders(status, id) 覆蓋子查詢,避免回表。
TABLESAMPLE (MySQL 8.0.31+ / MariaDB 10.3+)SELECT * FROM orders TABLESAMPLE SYSTEM (1) WHERE status='paid' LIMIT 10;
-- SYSTEM (1) 表示 1% 頁面採樣,極快但非精確隨機
SELECT M.*, SS.SensorCode, SS.SensorStatus, TP.PricingStrategyId
FROM (
SELECT T.*, BS.ParkStatus, BS.ChangeTime, CA.CantonName, SE.SectionName
FROM (
SELECT A.*, B.BerthId, B.BerthCode, B.BerthAddress, B.BerthStatus, B.LineDirection, B.CantonId, B.SectionId
FROM (SELECT AreaId, AreaCode, AreaName FROM SYS_Area WHERE AreaCode='110') A
LEFT JOIN SYS_Berth B ON B.AreaId = A.AreaId
) T
JOIN SYS_BerthStatus BS ON T.BerthCode = BS.BerthCode
JOIN SYS_Canton CA ON T.CantonId = CA.CantonId
JOIN SYS_Section SE ON T.SectionId = SE.SectionId
) M
LEFT JOIN SYS_Sensor SS ON M.BerthCode = SS.BerthCode
LEFT JOIN TRA_PricingBerth TP ON TP.BerthCode = M.BerthCode
-- 關鍵:最內層先過濾 (AreaCode='110'),逐層 JOIN,關鍵欄位皆有索引