MySQL order by 排序使用的字段有重複值導致排序隨機的情況

生產環境一個列表頁的分頁查詢sql:

SELECT *
FROM ap_clue a LEFT JOIN ap_dealer d ON a.intention_dealer_id = d.dealer_id
ORDER BY a.date_create DESC limit 90,5;

根據ap_clue表中的date_create字段倒敘排列,但是ap_clue表中很多記錄date_create字段是相同的,此時的分頁結果是MySQL根據date_create隨機返回的。(生產環境MySQL版本:5.7.26-log)

     查了一下MySQL官網,對這種情況做了介紹:

https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html

“If multiple rows have identical values in the ORDER BY columns, the server is free to return those rows in any order, and may do so differently depending on the overall execution plan. In other words, the sort order of those rows is nondeterministic with respect to the nonordered columns.”

翻譯:如果在ORDER BY列中有多個行具有相同的值,則服務器可以自由以任何順序返回這些行,並且根據整體執行計劃的不同,返回值可能會有所不同。 換句話說,這些行的排序順序相對於無序列是不確定的。

基於這個,就知道爲什麼會出現這個問題了。這個SQL主要問題是會可能導致分頁查詢查不出一些記錄,如果date_create字段相同的記錄多於分頁每頁記錄數,就會導致一些記錄上一頁出現了,下一頁又查出了(MySQL隨機返回導致的),而一些數據可能就查不出來了。怎麼解決這個問題,想必大家頁想到了,MySQL官網上也給出了一種方案:

“If it is important to ensure the same row order with and without LIMIT, include additional columns in the ORDER BY clause to make the order deterministic. For example, if id values are unique, you can make rows for a given category value appear in id order by sorting like this:”

在ORDER BY子句中包括其他列以使順序確定,比如可以使用主鍵id等。上面的SQL可以修改下:

SELECT *
FROM ap_clue a LEFT JOIN ap_dealer d ON a.intention_dealer_id = d.dealer_id
ORDER BY a.date_create DESC ,a.clue_id limit 90,5;

以上,問題得到解決。

我在測試環境造了一些date_create相同的記錄,分頁查詢,一樣的sql查詢,但是卻沒有出現隨機返回的情況。使用explain命令查看各自的執行計劃:

1、生產環境MySQL版本信息:5.7.26-log

上面那個SQL的執行計劃:

2、測試環境MySQL版本信息:5.7.26-29-log

上面那個SQL的執行計劃:

兩個環境的表結構是一致的,但是執行計劃確實不一樣,生產環境的還用到了臨時表(Using temporary),爲什麼會出現這樣的差異,一時沒找到答案,後續還要再研究下。

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