如何隨機獲取表中幾行記錄

2021-10-24 09:28:35 字數 1919 閱讀 8709

用 order by rand() 來實現這個邏輯。

explain

select name from t_user order

by rand(

)limit

2;

這個語句的意思很直白,隨機排序取前 3 個。雖然這個 sql 語句寫法很簡單,但執行流程卻有點複雜的。

可以看到extra欄位中顯示using temporary 表示使用了臨時表,using filesort,表示的是需要執行排序操作。 使用了排序操作。

整個操作流程:

建立乙個臨時表, 表裡有兩個字段,第乙個欄位是 double 型別,為了後面描述方便,記為字段 r,第二個欄位是 varchar(64) 型別,記為字段 w。並且,這個表沒有建索引。

從t_user表中取出所有的name欄位放入臨時表中, 並每條記錄使用rand()函式生成乙個隨機數, 並把隨機數賦值給r欄位

把臨時表中的r和w欄位的值放入sort_buffer中根據r欄位進行排序,

排序完成後, 取出全面三個記錄, 把w欄位的值返回給客戶端,

可以看到上面的整個流程 會把全表掃瞄兩次,第一次是把所有記錄掃瞄出來放入臨時表, 第二次把臨時把的資料掃瞄出來放入到sort_buffer中。 代價還是很高的。

tmp_table_size 值的設定可以限制記憶體臨時表的大小, 預設16m。 如果記憶體臨時表的大小超出了這個限制就會使用磁碟臨時表。

上面的語句中 獲取到的只是前面的2個記錄, 如果sort_buffer不夠用了,會使用臨時檔案,使用臨時檔案了就會使用歸併排序演算法 ,但是只是去前面2行記錄,使用歸併排序並不必要, mysql會進行優化 使用了優先佇列排序演算法。

優先佇列排序演算法其實就是選擇排序中的堆排序, 但是它不會構建整個堆, 只會構建包含2個節點的堆, 然後把後面的資料以此和這個堆進行比較,如果小於對堆中節點的值就替換掉這個節點,這樣比較完成後這個堆就是符合要求的最小的兩行記錄了。 使用的記憶體也會很小。

但是如果我們的limit後面的值比較大, sort_buffer裝不下所有的排序行,還是會使用歸併排序的。 使用優先排序的前提是sort_buffer夠用。

方法一

先取得最大id值max和最小id值min .

使用應用程式獲取max和min中間的乙個隨機數 r

使用 select * from table where id >= r limit 3

當然我這個流程使用到了應用程式,可能會出現問題, 如果在取隨機數r的時候表的最大最小id改變了,後面查詢的時候可能會查出0條。

解決辦法就是三步操作都放到乙個事務中, 由於rr的隔離級別會沒有問題的, 也可以三步操作都使用sql語句來完成, sql也是乙個很強大的程式語言的。

由於表記錄中間有空洞, 比如表中三條記錄的id值為 1, 2, 10000000. 使用上面的方法一, 明顯的id為10000000的概率大多了。

方法二

取得表的總行數c

生成隨機數y, 這個y的範圍從 [ 0, c )

在使用 select * from table limit y, 3 獲取隨機的三行

這個方法二解決了概率不均衡的問題。 但是這個方法第一步會掃瞄表的總行數, 第三步會掃瞄y+1行, 總計掃瞄了c+y+1行。 代價比方法一要搞很多。 但是代價還是比使用order by rand() 的代價低多了。

方法一在資料的id連續的情況下是沒有問題的, 並且執行效率很高的, 這個需要根據你的業務資料的id情形來判斷是否使用了。 如果id已經無法修改了,它本身就是不均勻的, 這個使用我們可以專門建立乙個排序字段, 自己設定裡面的值是連續的, 在使用這個排序欄位來進行方法一操作。

方法二的代價比較大一點,但是為通用解決方案。

Oracle獲取隨機記錄

最近在做乙個小的考試系統,需要用到隨機抽取題目,於是就從網上搜到如下方法 1.dbms random包 select from select from tablename order by dbms random.value where rownum n 注 dbms random包需要手工安裝,位...

mysql隨機獲取記錄

size medium mysql的隨機抽取實現方法。舉個例子,要從tablename表中隨機提取一條記錄,大家一般的寫法就是 select from tablename order by rand limit 1 但是,後來我查了一下mysql的官方手冊,裡面針對rand 的提示大概意思就是,在o...

mysql隨機獲取記錄

mysql隨機獲取記錄 mysql的隨機抽取實現方法。舉個例子,要從tablename表中隨機提取一條記錄,大家一般的寫法就是 select from tablename order by rand limit 1 但是,後來我查了一下mysql的官方手冊,裡面針對rand 的提示大概意思就是,在o...