mysql orderby limit 翻頁數據重復的問題


在mysql中我們通常會采用limit來進行翻頁查詢,比如limit(0,10)表示列出第一頁的10條數據,limit(10,10)表示列出第二頁。但是,當limit遇到order by的時候,可能會出現翻到第二頁的時候,竟然又出現了第一頁的記錄。

具體如下:

SELECT `post_title`,`post_date` FROM post WHERE `post_status`='publish' ORDER BY view_count desc LIMIT 5,5 

使用上述SQL查詢的時候,很有可能出現和LIMIT 0,5相同的某條記錄,而如果使用:

SELECT * FROM post WHERE post_status='publish' ORDER BY view_count desc LIMIT 5,5
則不會出現重復的情況。但是,由於post表的字段很多,我僅僅希望用這兩個字段,不想把post_content也查出來。為了解決這個情況,我在ORDER BY后面使用了兩個排序條件來解決這個問題。

SELECT `post_title`,`post_date` FROM post WHERE `post_status`='publish' ORDER BY view_count desc,ID asc LIMIT 5,5 

按理來說,mysql的排序默認情況下是以主鍵ID作為排序條件的,也就是說,如果在view_count相等的情況下,主鍵ID作為默認的排序條件,不需要我們多此一舉加ID asc。但是事實就是,mysql再order by和limit混用的時候,出現了排序的混亂情況。其后的機理我尚不得而知,在閱讀這篇文章后,好像有所領悟,下面做一下猜測。

這篇文章的解釋是:

在MySQL 5.6的版本上,優化器在遇到order by limit語句的時候,做了一個優化,即使用了priority queue。……

使用 priority queue 的目的,就是在不能使用索引有序性的時候,如果要排序,並且使用了limit
n,那么只需要在排序的過程中,保留n條記錄即可,這樣雖然不能解決所有記錄都需要排序的開銷,但是只需要 sort buffer
少量的內存就可以完成排序。

之所以5.6出現了第二頁數據重復的問題,是因為 priority queue使用了堆排序的排序方法,而堆排序是一個不穩定的排序方法,也就是相同的值可能排序出來的結果和讀出來的數據順序不一致。

5.5 沒有這個優化,所以也就不會出現這個問題。

也就是說,mysql5.5是不存在本文提到的問題的,5.6版本之后才出現了這種情況。

我們再看下mysql解釋sql語言時的執行順序:

(7)     SELECT (8) DISTINCT <select_list> (1) FROM <left_table> (3) <join_type> JOIN <right_table> (2) ON <join_condition> (4) WHERE <where_condition> (5) GROUP BY <group_by_list> (6) HAVING <having_condition> (9) ORDER BY <order_by_condition> (10) LIMIT <limit_number> 

在我們本文的案例sql中,執行順序依次為form… where… select… order by… limit…

由於上述priority queue的原因,在完成select之后,所有記錄是以堆排序的方法排列的,在進行order by時,僅把view_count值大的往前移動。但由於limit的因素,排序過程中只需要保留到5條記錄即可,view_count並不具備索引有序性,所以當第二頁數據要展示時,mysql見到哪一條就拿哪一條,因此,當排序值相同的時候,第一次排序是隨意排的,第二次再執行該sql的時候,其結果應該和第一次結果一樣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM