日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

Mysql order by与limit混用陷阱

發(fā)布時(shí)間:2025/1/21 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mysql order by与limit混用陷阱 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Mysql中我們常常用order by來(lái)進(jìn)行排序,使用limit來(lái)進(jìn)行分頁(yè),當(dāng)需要先排序后分頁(yè)時(shí)我們往往使用類似的寫法select * from 表名 order by 排序字段 limt M,N。但是這種寫法卻隱藏著較深的使用陷阱。在排序字段有數(shù)據(jù)重復(fù)的情況下,會(huì)很容易出現(xiàn)排序結(jié)果與預(yù)期不一致的問(wèn)題。

比如現(xiàn)在有一張user表,表結(jié)構(gòu)及數(shù)據(jù)如下:

表結(jié)構(gòu)

表數(shù)據(jù)

現(xiàn)在想根據(jù)創(chuàng)建時(shí)間升序查詢user表,并且分頁(yè)查詢,每頁(yè)2條,那很容易寫出sql為:select * from user order by create_time limit pageNo,2;

在執(zhí)行查詢過(guò)程中會(huì)發(fā)現(xiàn):
1
、查詢第一頁(yè)數(shù)據(jù)時(shí):

第一頁(yè)查詢結(jié)果

2、查詢第四頁(yè)數(shù)據(jù)時(shí):

第四頁(yè)查詢結(jié)果

user表共有8條數(shù)據(jù),有4頁(yè)數(shù)據(jù),但是實(shí)際查詢過(guò)程中第一頁(yè)與第四頁(yè)竟然出現(xiàn)了相同的數(shù)據(jù)。

這是什么情況?難道上面的分頁(yè)SQL不是先將兩個(gè)表關(guān)聯(lián)查詢出來(lái),然后再排好序,再取對(duì)應(yīng)分頁(yè)的數(shù)據(jù)嗎???

上面的實(shí)際執(zhí)行結(jié)果已經(jīng)證明現(xiàn)實(shí)與想像往往是有差距的,實(shí)際SQL執(zhí)行時(shí)并不是按照上述方式執(zhí)行的。這里其實(shí)是Mysql會(huì)對(duì)Limit做優(yōu)化,具體優(yōu)化方式見(jiàn)官方文檔:https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
這個(gè)是5.7版本的說(shuō)明,提取幾個(gè)問(wèn)題直接相關(guān)的點(diǎn)做下說(shuō)明。

Paste_Image.png

上面官方文檔里面有提到如果你將Limit row_countorder by混用,mysql會(huì)找到排序的row_count行后立馬返回,而不是排序整個(gè)查詢結(jié)果再返回。如果是通過(guò)索引排序,會(huì)非常快;如果是文件排序,所有匹配查詢的行(不帶Limit的)都會(huì)被選中,被選中的大多數(shù)或者全部會(huì)被排序,直到limit要求的row_count被找到了。如果limit要求的row_count行一旦被找到,Mysql就不會(huì)排序結(jié)果集中剩余的行了。

這里我們查看下對(duì)應(yīng)SQL的執(zhí)行計(jì)劃:

Paste_Image.png

可以確認(rèn)是用的文件排序,表確實(shí)也沒(méi)有加額外的索引。所以我們可以確定這個(gè)SQL執(zhí)行時(shí)是會(huì)找到limit要求的行后立馬返回查詢結(jié)果的。

不過(guò)就算它立馬返回,為什么分頁(yè)會(huì)不準(zhǔn)呢?

官方文檔里面做了如下說(shuō)明:

Paste_Image.png

如果order by的字段有多個(gè)行都有相同的值,mysql是會(huì)隨機(jī)的順序返回查詢結(jié)果的,具體依賴對(duì)應(yīng)的執(zhí)行計(jì)劃。也就是說(shuō)如果排序的列是無(wú)序的,那么排序的結(jié)果行的順序也是不確定的。

基于這個(gè)我們就基本知道為什么分頁(yè)會(huì)不準(zhǔn)了,因?yàn)槲覀兣判虻淖侄问?/span>create_time,正好又有幾個(gè)相同的值的行,在實(shí)際執(zhí)行時(shí)返回結(jié)果對(duì)應(yīng)的行的順序是不確定的。對(duì)應(yīng)上面的情況,第一頁(yè)返回的name8的數(shù)據(jù)行,可能正好排在前面,而第四頁(yè)查詢時(shí)name8的數(shù)據(jù)行正好排在后面,所以第四頁(yè)又出現(xiàn)了。

那這種情況應(yīng)該怎么解決呢?

官方給出了解決方案:

Paste_Image.png

如果想在Limit存在或不存在的情況下,都保證排序結(jié)果相同,可以額外加一個(gè)排序條件。例如id字段是唯一的,可以考慮在排序字段中額外加個(gè)id排序去確保順序穩(wěn)定。

所以上面的情況下可以在SQL再添加個(gè)排序字段,比如fund_flowid字段,這樣分頁(yè)的問(wèn)題就解決了。修改后的SQL可以像下面這樣:
SELECT * FROM?
user?ORDER BY create_time,id LIMIT 6,2;

再次測(cè)試問(wèn)題解決!!

與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的Mysql order by与limit混用陷阱的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。