mysql同時使用order by和limit查詢時的一個嚴重隱患,mysqllimit
我經常使用order by和limit來做資料分頁顯示並排序,一直也沒發現過什麼問題。但這兩天缺遇到一個嚴重的問題,在按時間戳記升序排列並用limit分批讀取資料時,卻發現在某些記錄丟失了,表中明明有的記錄確死活讀取不到。研究了大半天終於發現了問題所在,記錄一下以防忘記,也是給大家提個醒。
問題重現工具和原料資料庫:
Ver 14.14 Distrib 5.6.11, for Linux (x86_64) using EditLine wrapper
表結構:
欄位 |
類型 |
說明 |
id |
int(10) |
主鍵 |
pay_time |
int(10) |
時間戳記,有索引 |
flag |
tinyint(1) |
類型標識,用於分類篩選 |
資料
大概5000條資料, 大部分記錄的flag都等於0,pay_time欄位時間戳記格式都正確
需求
篩選出flag=0的記錄,按pay_time升序依次讀取所有資料。
處理方式
使用limit分批讀取資料,如:
select id, pay_time from order_customer_new where flag=0 order by pay_time asc, id asc limit 250, 10;
發現問題
在讀取資料的過程中,發現有時間戳記相等的記錄,分兩次讀取出來時,可能會丟失一條記錄。見,id=465的記錄就丟失了。
問題分析與猜測
當排序值相等,其先後順序的不確定的。這裡我猜想:當465和466處於limit末尾時466排在前面,而當處於limit開頭時,466缺排到後面去了。所以465丟失了,466出現了兩次。
排序值相等時,其順序的不確定應該是其結果不可預測。但真正進行排序時應該會採取一定的規則以確定唯一的排序結果,也就是說,即使有相等的排序值,多次排序的結果應該是一樣的。從以前的使用經曆看,mysql是這麼做的。但這次遇到的問題似乎說明mysql並不是這樣的。不知道mysql本來就是如此,還是一個bug。
解決辦法
既然猜想此問題是因為排序值相等造成順序不確定引起的,那麼就試試增加排序條件讓其排序結果是確定的、唯一的。一試果然OK,如所示,465出來了。
請求支援
我對mysql的底層實現和資料庫原理不是很瞭解,完全不明白mysql為什麼會出現這種問題。若哪位朋友能解釋一二,不勝感激!