采坑筆記——mysql的order by和limit排序問題

背景說明

今天寫出一個(gè)十分弱智的bug,記錄一下,提醒自己以后別這種犯錯(cuò),不怕丟人哈~
在寫一個(gè)分頁查詢記錄的sql時(shí),要根據(jù)添加的時(shí)間逆序分頁輸出,之前的寫法是醬紫

select 
    record.a, 
    y.c
from 
    (
        select 
            a,b 
        from 
            x
        order by timestamp desc
        limit 0,10
    ) record
left join y
on record.b = y.d;

因?yàn)橐恍┬碌男枨?,要在后面加一些where條件,limit操作不能在嵌套查詢里面加了,于是乎把limit 0,10提出來放到最外面,結(jié)果order by還留在里面,我當(dāng)時(shí)想嵌套查詢出來的record表已經(jīng)按timestamp字段逆序排列了,再left另一張表,最終再limit出來的結(jié)果應(yīng)該也是逆序的,但結(jié)果卻很打臉,是正序的。

分析原因

  1. 首先控制變量,代碼回滾到之前,把后來加的各種邏輯都去掉,還原到上述sql,只把limit 0,10移到最后,發(fā)現(xiàn)timestamp是正序的,那么問題應(yīng)該就出在這里了,與后來加的其他邏輯沒有關(guān)系。
  2. 那么再試一下刪掉limit操作,結(jié)果timestamp是無序的!這不可能啊,于是認(rèn)真看了下數(shù)據(jù),發(fā)現(xiàn)一些規(guī)律,可能是按y表的自增id或created_at時(shí)間字段排序的(因?yàn)檫@兩個(gè)字段是索引字段),那么到這里,我們至少可以得到一個(gè)簡單的結(jié)論,就是聯(lián)表查詢結(jié)果,不是按照嵌套查詢中的order by排序的,現(xiàn)在正向一看,確實(shí)不可能按這個(gè)排序,因?yàn)槔ㄌ柪锩娴倪壿媽ㄌ柾馐遣豢梢姷摹?/li>
  3. 還有個(gè)問題,上述去掉limit后,最終不是按left join主表的順序輸出,按照我們常理想象,mysql是循環(huán)主表的記錄去關(guān)聯(lián)另一張表,那么輸出的順序應(yīng)該還是主表的順序啊,但結(jié)果卻是按另一張表的字段排序的,這又是為什么呢?
    去官方手冊中找找線索,發(fā)現(xiàn)order by模塊中有這么一句話。


    order by模塊

    再去limit模塊中看一下


    limit模塊

    從以上兩個(gè)截圖中,我們可以發(fā)現(xiàn)一些端倪,limit操作會對查詢有一些優(yōu)化,查詢到指定條數(shù)的數(shù)據(jù),就可以提前結(jié)束了,比如我們本文中的left操作,拿到10條結(jié)果就結(jié)束查詢線程,返回客戶端。我猜測,如果沒有l(wèi)imit操作,反正全部都要join,可能mysql會對循環(huán)邏輯做一些優(yōu)化,不一定要按主表來循環(huán),思想類似于java編譯中的重排序,也對應(yīng)了上面截圖中的那句話。

解決方案

采用最簡單、最粗暴的方式,直接把order by 和 limit操作放到最外面就ok啦,其實(shí)效率上并沒有什么降低,只要索引建的合理即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容