今天項目提測,被測出了一個奇怪的bug,第一頁最后一條數(shù)據(jù)和第二頁的第一條數(shù)據(jù)重復(fù)了,并且神奇的丟失了一個條數(shù)據(jù),下面開始來分析一下這個場景。

第一頁

第二頁
場景為對一些作業(yè)進行按時間排序,但是有的作業(yè)時間是相同的。
對代碼進行查看發(fā)現(xiàn),代碼并沒有什么問題,只是簡單的查詢?nèi)磿r間排序分頁返回給前端。
所以去看一看mysql對limit的解釋,從官方文檔中發(fā)現(xiàn)了這樣一句話
如果多個行在列中具有相同的值ORDER BY,則服務(wù)器可以按任意順序自由返回這些行,并且根據(jù)總體執(zhí)行計劃可能會有所不同。換句話說,這些行的排序順序?qū)τ跓o序列是非確定性的。
根據(jù)這句話我們可以發(fā)現(xiàn),在order by的值相同時,返回的順序不一定一致。
下面我們來思考一下造成這個坑的原因是什么呢?
在MySQL 5.6版本,優(yōu)化器在遇到order by xxx limit x,x 時,會做一個優(yōu)化,使用優(yōu)先隊列,來進行排序,這樣的好處在于在排序過程中,僅保留需要的n條數(shù)據(jù)即可。
如果你已經(jīng)熟悉了各大排序的特點,那么可以知道堆排序是不穩(wěn)定排序,所以導(dǎo)致了今天的這個問題。
下面分享一下各個排序的穩(wěn)定性:
- 冒泡排序:穩(wěn)定
- 選擇排序:不穩(wěn)定,每次選擇最小的與之前交換,可能會將相同元素的順序打亂
- 插入排序:穩(wěn)定
- 快速排序:不穩(wěn)定,不穩(wěn)定發(fā)生在key與相遇點進行交換時。
- 歸并排序:穩(wěn)定
- 基數(shù)排序:穩(wěn)定
- 希爾排序:不穩(wěn)定,插入順序不同,相同元素可能在不同的插入順序中分別排序
- 堆排序:不穩(wěn)定,可能子節(jié)點與父節(jié)點進行交換時,將兩個相同元素順序打亂,5(left) 6(root) 5(right) -> 5 5 6,此時right位于5的left
下面說一下問題的解決方法:
- order by后加一個唯一字段(id)進行排序
- 給order by字段加上索引
世上沒有解決不了的bug,也許只是方向不對