java混合分页_坑,MySQL中 order by 与 limit 混用,分页会出现问题!
在Mysql中我們常常用order by來進行排序,使用limit來進行分頁,當需要先排序后分頁時我們往往使用類似的寫法select * from 表名 order by 排序字段 limt M,N。
但是這種寫法卻隱藏著較深的使用陷阱。在排序字段有數據重復的情況下,會很容易出現排序結果與預期不一致的問題。
比如現在有一張user表,表結構及數據如下:
表結構
表數據
現在想根據創建時間升序查詢user表,并且分頁查詢,每頁2條,那很容易寫出sql為:select * from user order by create_time limit pageNo,2;
在執行查詢過程中會發現:
1、查詢第一頁數據時:
第一頁查詢結果
2、查詢第四頁數據時:
第四頁查詢結果
user表共有8條數據,有4頁數據,但是實際查詢過程中第一頁與第四頁竟然出現了相同的數據。
這是什么情況?難道上面的分頁SQL不是先將兩個表關聯查詢出來,然后再排好序,再取對應分頁的數據嗎???
上面的實際執行結果已經證明現實與想像往往是有差距的,實際SQL執行時并不是按照上述方式執行的。這里其實是Mysql會對Limit做優化,具體優化方式見官方文檔:
https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
這個是5.7版本的說明,提取幾個問題直接相關的點做下說明。
Paste_Image.png
上面官方文檔里面有提到如果你將Limit row_count與order by混用,mysql會找到排序的row_count行后立馬返回,而不是排序整個查詢結果再返回。如果是通過索引排序,會非常快;
這里我們查看下對應SQL的執行計劃:
Paste_Image.png
可以確認是用的文件排序,表確實也沒有加額外的索引。所以我們可以確定這個SQL執行時是會找到limit要求的行后立馬返回查詢結果的。
不過就算它立馬返回,為什么分頁會不準呢?
官方文檔里面做了如下說明:
Paste_Image.png
基于這個我們就基本知道為什么分頁會不準了,因為我們排序的字段是create_time,正好又有幾個相同的值的行,在實際執行時返回結果對應的行的順序是不確定的。對應上面的情況,第一頁返回的name為8的數據行,可能正好排在前面,而第四頁查詢時name為8的數據行正好排在后面,所以第四頁又出現了。
那這種情況應該怎么解決呢?
官方給出了解決方案:
Paste_Image.png
如果想在Limit存在或不存在的情況下,都保證排序結果相同,可以額外加一個排序條件。例如id字段是唯一的,可以考慮在排序字段中額外加個id排序去確保順序穩定。
所以上面的情況下可以在SQL再添加個排序字段,比如fund_flow的id字段,這樣分頁的問題就解決了。修改后的SQL可以像下面這樣:
SELECT?*?FROM?`user`?ORDER?BY?create_time,id?LIMIT?6,2;
再次測試問題解決!!
總結
以上是生活随笔為你收集整理的java混合分页_坑,MySQL中 order by 与 limit 混用,分页会出现问题!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java range类_Java即时类|
- 下一篇: stl vector 函数_vector