如何正確地顯示隨機訊息?讀後總結

2021-09-26 08:41:42 字數 3002 閱讀 7078

背景:有個單詞表,隨機顯示3個單詞

建表語句與初始化語句

mysql> create tablewords(

idint(11) not null auto_increment,

wordvarchar(64) default null,

primary key (id)

) engine=innodb;

delimiter ;;

create procedure idata()

begin

declare i int;

set i=0;

while i<10000 do

insert into words(word) values(concat(char(97+(i div 1000)), char(97+(i % 1000 div 100)), char(97+(i % 100 div 10)), char(97+(i % 10))));

set i=i+1;

end while;

end;;

delimiter ;

call idata();

隨機顯示3個單詞用什麼sql

一般可能會用到的 order by rand()

select word from words order by rand() limit 3;

我們用explain查詢語句執行。

關注extra欄位using temporary表示使用臨時表,using filesort表示需要執行排序。

對於記憶體臨時表的排序來說,(ps:記憶體臨時表的預設引擎是memory)

innodb為了減少磁碟的訪問,優先選擇全欄位排序

記憶體表memory回表無須訪問磁碟,優先選擇rowid排序。

語句執行流程:

建立臨時表,引擎為memory,有r,w兩個字段,沒有建索引

2.從words表中,俺主鍵順序取出所有的word值,對於每乙個word值,呼叫rand()函式生成乙個大於0小於1的隨機小數。把隨機小數與word存入臨時表的rw欄位

3.臨時表安裝r欄位排序。

4.初始化sort_buffer,(由於用rowid排序)只有這個r欄位與預設rowid欄位。

5.從臨時表中取出r值與rowid,存入sort_buffer。(這個過程設計記憶體表的全表掃瞄會更加掃瞄行數。)

6.sort_buffer根據r值排序。

7.排序後取前三個結果rowid,到記憶體表取w欄位返回給客戶端。

小結:order by rand()使用了記憶體臨時表,記憶體臨時表排序的時候使用了rowid排序。

磁碟臨時表

tmp_table_size這個引數限制了記憶體臨時表的大小。預設值是16m,如果臨時表的大小超過了tmp_table_size這個值。則記憶體臨時表會轉為磁碟臨時表

磁碟臨時表預設引擎使用innodb。由internal_tmp_disk_storage_engine控制的。

為了復現這個過程,把tmp_table_size=1024 sort_buffer_size=32768

max_length_for_sort_data=16

set tmp_table_size=1024;

set sort_buffer_size=32768;

set max_length_for_sort_data=16;

/* 開啟 optimizer_trace,只對本執行緒有效 */

set optimizer_trace=『enabled=on』;

/* 執行語句 */

select word from words order by rand() limit 3;

/* 檢視 optimizer_trace 輸出 */

select * frominformation_schema.optimizer_trace\g

檢視optimizer_trace的結果。

number_of_tmp_files為0,不需要臨時檔案。

mysql5.6後引入了優先佇列排序演算法(大小根堆演算法,不需要將所有的資料進行排序。)

select city,name,age from t where city=『杭州』 order by name limit 1000 ;

之前我們只有三條記錄,需要維護堆的大小只有3行。

但是現在我們將記錄行擴充套件到了1000行,超過了設定的sort_buffer_size,只能選用歸併排序。

小結:order by rand()不管用什麼臨時表,計算過程都比較複雜。需要掃瞄大量的行,且排序過程消耗大量的資源。

隨機排序方法

隨機演算法1:

select max(id),min(id) into @m,@n from t;

set @x=floor((@m-@n+1)*rand()+@n);

select * from t where id >=@x limit 1;

1.獲取這個表主鍵id的最大值m與最小值n

2.用隨機函式生成乙個m~n之間的數x

3.取不小於x的第乙個id的行。

缺點id如果不連續,則m~n之前的空洞會影響其他行的概率。

隨機演算法2

select count(*) into @c from t;

set @y = floor(@c * rand())//取整數部分

set @sql=concat("select * from t limit ", @y, 「,1」);

prepare stmt from @sql;

execute stmt;

deallocate prepare stmt;

1.取整個表的行數c。

2.用隨機函式取得1~c之前的隨機值

3.再用limit y,1取得一行

mysql處理limit y,1的做法是按順序讀入,丟棄前y個,然後把下個作為結果返回。掃瞄行數會加上y。 掃瞄行數增加了,但是解決了概率平均的問題。

如何正確地寫出單例模式

發表於 2014 08 28 分類於 程式設計 閱讀次數 50513 單例模式算是設計模式中最容易理解,也是最容易手寫 的模式了吧。但是其中的坑卻不少,所以也常作為面試題來考。本文主要對幾種單例寫法的整理,並分析其優缺點。很多都是一些老生常談的問題,但如果你不知道如何建立乙個執行緒安全的單例,不知道...

如何正確地部署防火牆?

防火牆在實際的部署應用過程當中,經常部署在閘道器的位置,也就是經常部署在網內和網外的乙個 中間分隔點 上,而就是在這樣乙個部署的環境中,也還存在著多種方式,且存在著許多 陷阱 本文將對幾種方式進行分析。請閱讀全文 防火牆在實際的部署應用過程當中,經常部署在閘道器的位置,也就是經常部署在網內和網外的乙...

如何正確地在MDK中使用關鍵

筆者在做移植時,將embest ide環境下的例程移到realview mdk的過程中,曾經遇到這樣乙個問題 在生成工程時,編譯全部通過,但在鏈結時提示許多符號未定義!如果讀者也遇到過這個問題,請繼續看下去,如果鏈結時提示未定義的變數是一些內聯函式 即使用了關鍵字 inline 那麼就是筆者遇到的問...