在 PHP 開發中,隨機從 MySQL 資料表抽取資料是常見需求,例如隨機推薦、抽獎活動或測試資料展示。本文整理了三種主流做法,並針對效能與適用場景進行說明,供開發者參考選擇。
ORDER BY RAND() 直接排序這是最直觀、程式碼最簡潔的方式:
SELECT * FROM `tablename` ORDER BY RAND() LIMIT 1;
將 LIMIT 後的數字調整即可一次抽取多筆。優點是語法簡單、無需額外程式邏輯;缺點是當資料量大時,RAND() 會導致全表掃描並產生臨時表,效能極差,不建議在超過萬筆資料的表上使用。
透過兩步驟避免 ORDER BY RAND() 的效能問題:
SELECT COUNT(*) AS count FROM recommendsLIMIT offset, length 讀取:$max_num = $row['count']; // 總筆數
srand((double)microtime() * 1000000); // 播種
$se_pos = rand(0, $max_num - 1); // 隨機起始位置
$length = 6; // 要抓幾筆
// 若剩餘筆數不足,調整起始位置
if (($max_num - $se_pos) <= $length) {
$se_pos = $max_num - $length;
}
$query = "SELECT * FROM recommends LIMIT $se_pos, $length";
此法只需一次 COUNT(*) 與一次索引範圍掃描,效能穩定,適合中大型資料表。
以下示範從資料庫 xyj 的 obj 表隨機抓取 30 筆資料:
<?php
$db = mysql_connect("localhost", "root");
mysql_select_db("xyj", $db);
$result = mysql_query("SELECT * FROM obj", $db);
$max_num = mysql_num_rows($result); // 取得總筆數
srand((double)microtime() * 10000000); // 產生隨機種子
$se_pos = rand(0, $max_num - 1); // 隨機起始位置
$length = 30; // 抓取筆數
$result_lim = mysql_query("SELECT * FROM obj LIMIT $se_pos, $length", $db);
$myrow_lim = mysql_fetch_array($result_lim);
printf("%s\n", $se_pos); // 顯示隨機起始位置
printf("%s\n", $myrow_lim["name"]); // 顯示隨機記錄的 name 欄位
?>
注意:範例使用已棄用的 mysql_* 函式,實際專案請改用 mysqli 或 PDO 並採用預處理語句,以確保安全性與相容性。
| 方法 | 適用資料量 | 優點 | 缺點 |
|---|---|---|---|
| ORDER BY RAND() | < 1 萬筆 | 語法最簡單 | 全表掃描、臨時表、效能差 |
| PHP 產生隨機 OFFSET | 任意大小 | 效能穩定、可控 | 需兩次查詢、略顯繁瑣 |
| 主鍵 ID 範圍隨機 (進階) | 超大表 | 極快、不掃描全表 | 需連續或近似連續 ID、邏輯較複雜 |
若資料表超過百萬筆且主鍵 ID 近似連續,可考慮「主鍵 ID 範圍隨機法」:先查 MIN(id)、MAX(id),在 PHP 產生隨機 ID,再用 WHERE id >= $rand_id ORDER BY id LIMIT 1 取得單筆,效能最佳。
專案初期或小資料量可直接用 ORDER BY RAND();正式上線、中大型資料表請採用「PHP 產生隨機 OFFSET」或「主鍵 ID 範圍隨機法」,並務必搭配 mysqli/PDO 預處理語句防止 SQL 注入。