萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 隨機查詢效能深度解析:從 ORDER BY RAND() 到百萬級優化

為什麼 ORDER BY RAND() 慢?

ORDER BY RAND() 會為每一行生成隨機數,然後在臨時表中排序,時間複雜度 O(N log N),且無法使用索引。資料量超過 1 萬行時,查詢時間呈指數級增長(15 萬行約 8 秒)。

優化方案對比

方案 A:建立輔助表(適用於離散值)

CREATE TABLE rand_number (num INT PRIMARY KEY);
INSERT INTO rand_number VALUES (-5),(-4),..., (5);

SELECT num FROM rand_number ORDER BY RAND() LIMIT 1;
  • 優點:可指定任意離散值集合
  • 缺點:範圍大時建表維護成本高

方案 B:數學函數生成連續隨機數(單次查詢)

-- 取 -5 到 5 的隨機整數
SELECT ROUND((0.5 - RAND()) * 2 * 5);
  • 優點:無需建表,範圍調整只需修改乘數
  • 缺點:只能生成連續整數

方案 C:JOIN + 索引掃描(百萬級推薦)

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 LIMIT 1;

核心原理:子查詢僅掃描索引計算隨機 ID,主查詢利用主鍵索引定位,避免全表排序。實測 15 萬行從 8 秒降至 0.01 秒。

方案 D:應用層生成隨機 ID 列表 + IN 查詢(最高效)

-- 1. 取得 ID 範圍
SELECT MIN(id), MAX(id) FROM `table`;

-- 2. PHP 生成 20 個隨機 ID(多取幾個防止刪除導致不足)
$idList = implode(',', array_map(fn() => mt_rand($min, $max), range(1, 20)));

-- 3. 單次查詢並保持隨機順序
SELECT * FROM `table` 
WHERE id IN ($idList) 
ORDER BY FIELD(id, $idList) 
LIMIT 12;
  • 優點:單次查詢,IO 開銷最小,3 萬行 12 筆僅 0.001 秒
  • 缺點:需處理 ID 空洞(刪除導致),多取幾個 ID 即可

效能總結表

方案15萬行單次耗時適用場景
ORDER BY RAND()8 秒+極小資料集(<1萬)
WHERE id >= RAND()*MAX(id)0.5 秒簡單隨機單筆
JOIN + 索引0.01 秒百萬級單筆/少量隨機
應用層 ID 列表 + IN0.001 秒高併發、批量隨機展示
copyright © 萬盛學電腦網 all rights reserved