一千萬個為什麽

搜索

MySQL的ORDER BY RAND()如何工作?


我一直在研究和測試如何在MySQL中進行快速隨機選擇。在這個過程中,我遇到了一些意想不到的結果,現在我並不完全確定我知道ORDER BY RAND()是如何工作的。

我一直認為,當你在表上執行ORDER BY RAND()時,MySQL會在表中添加一個新列,該列填充了隨機值,然後按該列對數據進行排序,然後例如你取以上隨機到達的值。我做了大量的谷歌搜索和測試,最後發現查詢周傑倫他博客中提供的確實是最快的解決方案:

SELECT * FROM Table T JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Table) AS x ON T.ID >= x.ID LIMIT 1;

雖然常見的ORDER BY RAND()在我的測試表上需要30-40秒,但他的查詢在0.1秒內完成了工作。他解釋了這在博客中是如何運作的,所以我將跳過這個,最後轉向奇怪的事情。

我的表是一個公共表,其中包含PRIMARY KEY id 和其他非索引的東西,如 usernameage 等。這就是我的意思努力解釋

SELECT * FROM table ORDER BY RAND() LIMIT 1; /*30-40 seconds*/
SELECT id FROM table ORDER BY RAND() LIMIT 1; /*0.25 seconds*/
SELECT id, username FROM table ORDER BY RAND() LIMIT 1; /*90 seconds*/

我有點希望看到所有三個查詢大致相同的時間,因為我總是在單個列上排序。但出於某種原因,這並沒有發生。如果您有任何想法,請告訴我。我有一個項目,我需要快速ORDER BY RAND(),我個人更喜歡使用

SELECT id FROM table ORDER BY RAND() LIMIT 1;
SELECT * FROM table WHERE id=ID_FROM_PREVIOUS_QUERY LIMIT 1;

其中,是的,比Jay的方法慢,但它更小,更容易理解。我的查詢相當大,有幾個JOIN和WHERE子句,雖然Jay的方法仍然有效,但查詢變得非常龐大和復雜,因為我需要在JOINed(在他的查詢中稱為x)子請求中使用所有JOIN和WHERE。

謝謝你的時間!

最佳答案

雖然沒有“rand()的快速訂單”這樣的事情,但是針對您的具體任務有一種解決方法。

For getting any single random row, you can do like this german blogger does: http://www.roberthartung.de/mysql-order-by-rand-a-case-study-of-alternatives/ (I couldn't see a hotlink url. If anyone sees one, feel free to edit the link.)

該文本是德語,但SQL代碼有點落在頁面上和大白框中,因此不難看出。

基本上他所做的就是制作一個能夠獲得有效行的程序。這會生成一個介於0和max_id之間的隨機數,嘗試獲取一行,如果它不存在,則繼續執行,直到找到一個。他允許通過將它們存儲在臨時表中來獲取x個隨機行,因此您可以重寫該過程以便更快地獲取一行。

這樣做的缺點是,如果你刪除很多行,並且存在巨大的差距,那麽它很可能會錯過很多次,使其失效。

更新:執行時間不同

SELECT * FROM table ORDER BY RAND()LIMIT 1;/ 30-40秒/

     

SELECT id FROM table ORDER BY RAND()LIMIT 1; /0.25秒/

     

SELECT id,username FROM table ORDER BY RAND()LIMIT 1;/ 90秒/

     

我有點希望看到所有三個查詢大致相同的時間,因為我總是在單個列上排序。但出於某種原因,這並沒有發生。如果您對此有任何想法,請與我們聯系。

它可能與索引有關。索引 id 並快速訪問,而將 username 添加到結果中,意味著它需要從每一行讀取它並將其放入內存表中。使用 * ,它還必須將所有內容讀入內存,但它不需要跳轉到數據文件,這意味著沒有時間丟失搜索。

僅當存在可變長度列(varchar/text)時才會產生差異,這意味著它必須檢查長度,然後跳過該長度,而不是僅跳過每行之間的設置長度(或0)。

轉載註明原文: MySQL的ORDER BY RAND()如何工作?

猜你喜歡