Mysql排序后分頁,因數據重復導致分頁數據紊亂的問題


背景

前不久在寫一個分頁接口的時候,在測試階段出現了排序結果紊亂且數據不正確的問題,那個接口是按照create_time進行排序的,但是對應的表中有很多相同create_time的數據,最后發現是因為 order by 排序的時候,如果排序字段中有多行相同的列值,則排序結果是不確定的。

復現

創建一個簡單表,並插入一些數據

mysql> desc people;
+-------------+-------------+------+-----+---------+----------------+
| Field       | Type        | Null | Key | Default | Extra          |
+-------------+-------------+------+-----+---------+----------------+
| id          | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| name        | varchar(20) | NO   |     | NULL    |                |
| create_time | bigint(20)  | NO   |     | NULL    |                |
+-------------+-------------+------+-----+---------+----------------+
3 行於數據集 (0.02 秒)

mysql> select * from people;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 1  | 張三 | 1           |
| 2  | 李四 | 2           |
| 3  | 王五 | 3           |
| 4  | 趙六 | 4           |
| 5  | 孫七 | 2           |
| 6  | 趙八 | 2           |
| 7  | 吳九 | 2           |
| 8  | 鄭十 | 2           |
+----+--------+-------------+
8 行於數據集 (0.02 秒)

分頁的寫法

分頁一般有2個參數:
page:表示第幾頁,從1開始,范圍[1,+∞)
pageSize:每頁顯示多少條記錄,范圍[1,+∞)

limit分頁公式

(1)limit分頁公式:curPage是當前第幾頁;pageSize是一頁多少條記錄

limit (curPage-1)*pageSize,pageSize
(2)用的地方:sql語句中

select 列 from 表名 limit(curPage-1)*pageSize,pageSize;

查詢復現

mysql> select * from people order by create_time asc limit 0,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 1  | 張三 | 1           |
| 2  | 李四 | 2           |
+----+--------+-------------+
2 行於數據集 (0.06 秒)

mysql> select * from people order by create_time asc limit 2,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 8  | 鄭十 | 2           |
| 6  | 趙八 | 2           |
+----+--------+-------------+
2 行於數據集 (0.09 秒)

mysql> select * from people order by create_time asc limit 4,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 6  | 趙八 | 2           |
| 7  | 吳九 | 2           |
+----+--------+-------------+
2 行於數據集 (0.04 秒)

mysql> select * from people order by create_time asc limit 6,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 3  | 王五 | 3           |
| 4  | 趙六 | 4           |
+----+--------+-------------+
2 行於數據集 (0.05 秒)

排序字段出現重復數據,這時可以加入第二個排序字段,提高排序的唯一性,

mysql> select * from people order by create_time asc,id asc limit 0,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 1  | 張三 | 1           |
| 2  | 李四 | 2           |
+----+--------+-------------+
2 行於數據集 (0.05 秒)

mysql> select * from people order by create_time asc,id asc limit 2,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 5  | 孫七 | 2           |
| 6  | 趙八 | 2           |
+----+--------+-------------+
2 行於數據集 (0.10 秒)

mysql> select * from people order by create_time asc,id asc limit 4,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 7  | 吳九 | 2           |
| 8  | 鄭十 | 2           |
+----+--------+-------------+
2 行於數據集 (0.05 秒)

mysql> select * from people order by create_time asc,id asc limit 6,2;
+----+--------+-------------+
| id | name   | create_time |
+----+--------+-------------+
| 3  | 王五 | 3           |
| 4  | 趙六 | 4           |
+----+--------+-------------+
2 行於數據集 (0.03 秒)

我們可以觀察到第一次的查詢中,缺少了‘孫七’的數據行,當我們加上了第二個排序字段時分頁數據變得正常了。

總結

MySQL 使用 limit 進行分頁時,可能會出現重復數據,通過加入 order by 子句可以解決,但是需要注意的是,如果排序字段有相同值的情況下,由於排序字段數據重復,可能會導致每次查詢排序后結果順序不同,分頁還是會出現重復數據,這時可以加入第二個排序字段,提高排序的唯一性,最好保證排序的字段在表中的值是唯一的,這樣就可以少寫一個排序字段,增加查詢效率,因為 order by 后面有多個排序字段時,無法用到索引。

 

本篇文章如有幫助到您,請給「翎野君」點個贊,感謝您的支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM