1、效率最高,但是當數據庫條數很少的時候,會出現記錄條數不固定的情況
SELECT * FROM object_images_rel WHERE status = 0 and image_id is null and id >= ((SELECT MAX(id) FROM object_images_rel)-(SELECT MIN(id) FROM object_images_rel)) * RAND() + (SELECT MIN(id) FROM object_images_rel) LIMIT 1
2、最原生的隨機算法,但是當數據庫記錄條數多的時候,運行會比較慢
SELECT * FROM object_images_rel where status = 0 and image_id is null ORDER BY rand() LIMIT 1
綜上,可以在記錄條數少的時候用rand,性能差不多,記錄數多的話使用方法1會比較好,以下是網上轉載的一篇文章,可以參考下:
http://blog.csdn.net/mengxiangone/article/details/8093347
若要在i ≤ R ≤ j 這個范圍得到一個隨機整數R ,需要用到表達式 FLOOR(i + RAND() * (j – i + 1))。例如, 若要在7 到 12 的范圍(包括7和12)內得到一個隨機整數, 可使用以下語句:
SELECT FLOOR(7 + (RAND() * 6));
以上摘抄自MySQL手冊
從 Mysql 表中隨機讀取數據不難,方法還挺多的,但是如果要考慮效率,得到一個快速的高效率的方法,那就不是一件簡單的事情了(至少對我來說不簡單)。
隨機獲得Mysql數據表的一條或多條記錄有很多方法,下面我就以users(userId,userName,password……)表(有一百多萬條記錄)為例,對比講解下幾個方法效率問題:
- select * from users order by rand() LIMIT 1
執 行該sql語句,老半天沒有反應,最后被迫手動停止執行,怎個傷人了得啊!后來我查了一下MYSQL手冊,里面針對RAND()的提示大概意思就是,在 ORDER BY從句里面不能使用RAND()函數,因為這樣會導致數據列被多次掃描,導致效率相當相當的低!效率不行,切忌使用! - SELECT * FROM users AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(userId) FROM `users`)-(SELECT MIN(userId) FROM users))+(SELECT MIN(userId) FROM users)) AS userId) AS t2 WHERE t1.userId >= t2.userId ORDER BY t1.userId LIMIT 1
執行該sql語句,用時0.031s,效率沒說的,相當的給力!心里那個爽啊,緊接着,我把”LIMIT 1“改為了”LIMIT 100“ 隨機取一百條記錄,用時0.048,給力吧。可是就在此時問題出現了,發現結果好像不是隨機的?為了驗證結果,又執行了N次,真不是隨機的, 問題出現在”ORDER BY t1.userId“這里,按userId排序了。隨機取一條記錄還是不錯的選擇,多條就不行了啊! - SELECT * FROM users WHERE userId >= ((SELECT MAX(userId) FROM users)-(SELECT MIN(userId) FROM users)) * RAND() + (SELECT MIN(userId) FROM users) LIMIT 1
執行該sql語句,用時0.039s,效率太給力了!接着我就把”LIMIT 1“改為了”LIMIT 10000“,用時0.063s。經過多次驗證,哥對燈發誓,結果肯定是隨機的!
結論:隨機取一條或多條記錄,方法都不錯! - 通過sql獲得最大值和最小值,然后通過php的rand生成一個隨機數randnum,再通過SELECT * FROM users WHERE userId >= randnum LIMIT 1,獲得一條記錄效率應該還可以,多條應該就不行了。
結論:方法1效率不行,切忌使用;隨機獲得一條記錄,方法2是相當不錯的選擇,采用JOIN的語法比直接在WHERE中使用函數效率還是要高一些的,不過方法3也不錯;隨機獲得多條記錄,方法3沒說的!
從Mysql某一表中隨機讀取n條數據的SQL查詢語句其他相關資料
SQL語句先隨機好ID序列,用 IN 查詢(飄易推薦這個用法,IO開銷小,速度最快):
$sql="SELECT MAX(id),MIN(id) FROM content";
$result=mysql_query($sql,$conn);
$yi=mysql_fetch_array($result);
$idmax=$yi[0];
$idmin=$yi[1];
$idlist='';
for($i=1;$i<=20;$i++){
if($i==1){ $idlist=mt_rand($idmin,$idmax); }
else{ $idlist=$idlist.','.mt_rand($idmin,$idmax); }
}
$idlist2="id,".$idlist;
$sql="select * from content where id in ($idlist) order by field($idlist2) LIMIT 0,12";
$result=mysql_query($sql,$conn);
$n=1;
$rnds='';
while($row=mysql_fetch_array($result)){
$rnds=$rnds.$n.". <a href='show".$row['id']."-".strtolower(trim($row['title']))."'>".$row['title']."</a><br />\n";
$n++;
}800萬數據隨機取一條的牛方法
mysql> select FLOOR(id*rand()) from test_rand where id=(select MAX(id) from test
_rand);
+------------------+
| FLOOR(id*rand()) |
+------------------+
| 5225551 |
+------------------+
1 row in set (0.00 sec)
語句簡單,速度慢的方法
SELECT * FROM table_name ORDER BY rand() LIMIT 5;
語句復雜,速度快的方法
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;
cjc注: ... AS id) AS t2 這里的 id, 也許該換成id2, 后面 WHERE t1.id >= t2.id 改成 WHERE t1.id >= t2.id2
摘自: http://www.dayanmei.com/blog.php/ID_203.htm
******************************************************************************************
Discuz中,隨機讀取論壇的幾個連續主題:
PHP里調用:
$s = "SELECT tid, fid, subject FROM {$tablepre}threads AS r1 JOIN (SELECT ROUND(RAND()*(SELECT MAX(tid) FROM {$tablepre}threads)) AS id) AS r2 WHERE (fid=13) and (r1.tid >= r2.id) ORDER BY r1.tid LIMIT 6";
$query = $db->query($s);
phpMyAdmin 中測試語句:
SELECT tid, fid, subject FROM cdb_threads AS r1 JOIN (SELECT ROUND(RAND()*(SELECT MAX(tid) FROM cdb_threads)) AS id) AS r2 WHERE (fid=13) and (r1.tid >= r2.id) ORDER BY r1.tid LIMIT 6
注意: 不可刪除 order by r1.tid, 否則總會固定出現最初的2行數據
******************************************************************************************
另一文章里使用了MIN()的版本:
通用語句:
SELECT *
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
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;
cjc注: ... AS id) AS t2 這里的 id, 也許該換成id2, 后面 WHERE t1.id >= t2.id 改成 WHERE t1.id >= t2.id2
Discuz 語句:
SELECT tid, fid,subject
FROM `cdb_threads` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(tid) FROM `cdb_threads`)-(SELECT MIN(tid) FROM `cdb_threads`))+(SELECT MIN(tid) FROM `cdb_threads`)) AS id) AS t2
WHERE t1.tid >= t2.id and fid=13 ORDER BY t1.tid LIMIT 5;
or
$s = "SELECT * FROM {$tablepre}threads AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(tid) FROM {$tablepre}threads)-(SELECT MIN(tid) FROM {$tablepre}threads))+(SELECT MIN(tid) FROM {$tablepre}threads)) AS id) AS t2 WHERE (t1.tid >= t2.id) and (fid=13) ORDER BY t1.tid LIMIT 6";
$query = $db->query($s);
cjc注: MIN(tid) 得到的通常是1, 所以加上MIN()的計算,不一定有必要.
*************************** 全文轉貼如下 ******************************************************
原文網址: http://jnote.cn/blog/mysql/mysql-rand-efficiency.html
mysql使用rand隨機查詢記錄效率測試 - 八月 8, 2007 | Posted by 老蔣
一直以為mysql隨機查詢幾條數據,就用
SELECT * FROM `table` ORDER BY RAND() LIMIT 5
就可以了。
但是真正測試一下才發現這樣效率非常低。一個15萬余條的庫,查詢5條數據,居然要8秒以上
查看官方手冊,也說rand()放在ORDER BY 子句中會被執行多次,自然效率及很低。
You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.
搜索Google,網上基本上都是查詢max(id) * rand()來隨機獲取數據。
SELECT *
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id ASC LIMIT 5;
但是這樣會產生連續的5條記錄。解決辦法只能是每次查詢一條,查詢5次。即便如此也值得,因為15萬條的表,查詢只需要0.01秒不到。
上面的語句采用的是JOIN,mysql的論壇上有人使用
SELECT *
FROM `table`
WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` )
ORDER BY id LIMIT 1;
我測試了一下,需要0.5秒,速度也不錯,但是跟上面的語句還是有很大差距。總覺有什么地方不正常。
於是我把語句改寫了一下。
SELECT * FROM `table`
WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM `table`)))
ORDER BY id LIMIT 1;
這下,效率又提高了,查詢時間只有0.01秒
最后,再把語句完善一下,加上MIN(id)的判斷。我在最開始測試的時候,就是因為沒有加上MIN(id)的判斷,結果有一半的時間總是查詢到表中的前面幾行。
完整查詢語句是:
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;
SELECT *
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
WHERE t1.id >= t2.id
ORDER BY t1.id LIMIT 1;
最后在php中對這兩個語句進行分別查詢10次,
前者花費時間 0.147433 秒
后者花費時間 0.015130 秒
看來采用JOIN的語法比直接在WHERE中使用函數效率還要高很多。
此方法limit如果大於1,返回的結果會是連續的記錄。