MySQL採用order by limit分段取數據彙總錯誤問題探究

MySQL採用order by limit分段取數據彙總錯誤問題探究

背景

前幾天接同事報問題:源數據一致的情況下,生產環境報表生成時而對,時而缺少確定的值。
查看源碼,報表生成採用SQL語句,

create_time >= xxx and create_time <= yyy order by create_time limit offset, 1; 

每次取指定時間段的一條記錄,然後累加指定字段生成。(先不考慮這種方式的效率)

結論

當多條記錄的create_time相同時,數據按create_time排序的結果是不恆定的(沒有冪等性);
導致有時某些記錄被取出多次,某些記錄沒有取到,從而表現爲報表時而對,時而缺少固定的值。

解決方案

分段取數據情況下,排序依據需要是具體唯一性的值,如數據庫主鍵。保證每次排序結果恆定,冪等。
補充:分段取數據,通常有時間參數,且索引最好能命中時間參數;所以排序最好是時間參數, 數據庫主鍵一起

過程

看代碼

每次取一條,邏輯雖然奇葩,但細看代碼無bug。

看日誌

沒有日誌,想辦法。以下是想辦法過程:

  1. 初想用Btrace,不熟Btrace埋點語法和如何使用非JDK類,遂放棄。

  2. MyBatis Mapper文件默認有logger,級別是info;SpringBoot Admin可以動態開啓指定logger;遂用SpringBoot Admin將對應Mapper日誌級別設置爲Trace。

  3. K8S指定pod日誌重定向到文件 kubectl logs -f --tail=10 pod名稱 > mapper.log

  4. 手動觸發報表生成邏輯,grep、awk採集mapper.log中sql的參數和結果。

  5. excel排序對比數據庫源數據和mapper.log採集的數據,找出差異:某條記錄被取2次,某條記錄未被取。

  6. 分析差異,被取2次記錄A和未被取記錄B的create_time相同,導致前一次獲取排序A、B,後一次獲取排序B、A;A被取2次,B未被取到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章