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

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

具體以下:sql

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

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

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混用的時候,出現了排序的混亂狀況。其後的機理我尚不得而知,在閱讀這篇文章後,好像有所領悟,下面作一下猜想。code

這篇文章的解釋是:orm

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

使用 priority queue 的目的,就是在不能使用索引有序性的時候,若是要排序,而且使用了limit
n,那麼只須要在排序的過程當中,保留n條記錄便可,這樣雖然不能解決全部記錄都須要排序的開銷,可是隻須要 sort buffer
少許的內存就能夠完成排序。索引

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

5.5 沒有這個優化,因此也就不會出現這個問題。get

也就是說,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的時候,其結果應該和第一次結果同樣。

這只是個人猜想,有理解的朋友,請幫忙解答。

相關文章
相關標籤/搜索