1. 程式人生 > >mysql分頁加排序資料重複問題解決方案

mysql分頁加排序資料重複問題解決方案

前言

又一次我給商品資料分頁並按照權重欄位排序,結果出現了資料重複問題,第一頁資料和第二頁資料有重複

其實,這個問題很簡單,如果你有仔細閱讀官檔的話。~^_^~

我們先來看看官檔是怎麼說的:

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.

One factor that affects the execution plan is LIMIT, so an ORDER BY query with and without LIMIT may return rows in different orders.

問題重現

本次實驗使用社群版 MySQL 5.6.26(因為小明出現問題的環境就是這個版本O(∩_∩)O~),下面先建立實驗環境和初始化測試資料:

[email protected] [(none)]>select @@version;
+------------+
| @@version  |
+------------+
| 5.6
.26-log | +------------+ 1 row in set (0.00 sec) [email protected] [(none)]>show variables like "sql_mode"; +---------------+------------------------+ | Variable_name | Value | +---------------+------------------------+ | sql_mode | NO_ENGINE_SUBSTITUTION | +---------------+------------------------+ 1
row in set (0.00 sec) [email protected] [(none)]>create database glon_ho; Query OK, 1 row affected (0.04 sec) [email protected] [(none)]>use glon_ho Database changed [email protected] [glon_ho]>create table glon( -> id int not null auto_increment primary key, -> name varchar(20) not null, -> create_time datetime not null, -> age tinyint unsigned default 18 -> ); Query OK, 0 rows affected (0.01 sec) [email protected] [glon_ho]>INSERT INTO `glon` VALUES (1, 'Eason Chan', '2017-05-02 08:10:10', 19),(2, 'Glon Ho', '2017-05-03 12:10:10', 18),(3, '趙敏', '2017-05-03 14:10:10', 17),(4, 'Jacky Cheung', '2017-05-02 14:00:00', 22),(5, '周芷若', '2017-05-02 14:00:00', 16),(6, 'Andy Lau', '2017-05-02 14:00:00', 50),(7, '至尊寶', '2017-05-02 14:00:00', 20),(8, '劉三姐', '2017-05-02 14:00:00', 19); Query OK, 8 rows affected (0.01 sec) Records: 8 Duplicates: 0 Warnings: 0 [email protected] [glon_ho]>select * from glon; +----+--------------+---------------------+------+ | id | name | create_time | age | +----+--------------+---------------------+------+ | 1 | Eason Chan | 2017-05-02 08:10:10 | 19 | | 2 | Glon Ho | 2017-05-03 12:10:10 | 18 | | 3 | 趙敏 | 2017-05-03 14:10:10 | 17 | | 4 | Jacky Cheung | 2017-05-02 14:00:00 | 22 | | 5 | 周芷若 | 2017-05-02 14:00:00 | 16 | | 6 | Andy Lau | 2017-05-02 14:00:00 | 50 | | 7 | 至尊寶 | 2017-05-02 14:00:00 | 20 | | 8 | 劉三姐 | 2017-05-02 14:00:00 | 19 | +----+--------------+---------------------+------+ 8 rows in set (0.00 sec)

這裡建立了一個 glon 表,欄位有自增 id, 姓名 name, 年齡 age, 及使用者註冊時間 create_time。

接著來複現問題

  • 根據使用者註冊時間 create_time 來排序:
[email protected] [glon_ho]>select * from glon ORDER BY create_time limit 0, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  1 | Eason Chan   | 2017-05-02 08:10:10 |   19 |
|  8 | 劉三姐       | 2017-05-02 14:00:00 |   19 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
|  7 | 至尊寶    | 2017-05-02 14:00:00 |   20 |
|  8 | 劉三姐    | 2017-05-02 14:00:00 |   19 |
|  2 | Glon Ho   | 2017-05-03 12:10:10 |   18 |
|  3 | 趙敏      | 2017-05-03 14:10:10 |   17 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)

可以看到兩次查詢結果中都出現了 id 為 8 的劉三姐,從上面初始化資料來看,總共有 8 條資料,現在不但分頁出現重複資料,還丟了一條!

問題確實重現了,不過先不急,我們再來試多幾組其他的排序方式。

  • create_time 和 age 組合排序
[email protected] [glon_ho]>select * from glon ORDER BY create_time,age limit 0, 4;
+----+------------+---------------------+------+
| id | name       | create_time         | age  |
+----+------------+---------------------+------+
|  1 | Eason Chan | 2017-05-02 08:10:10 |   19 |
|  5 | 周芷若     | 2017-05-02 14:00:00 |   16 |
|  8 | 劉三姐     | 2017-05-02 14:00:00 |   19 |
|  7 | 至尊寶     | 2017-05-02 14:00:00 |   20 |
+----+------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time,age limit 4, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
|  2 | Glon Ho      | 2017-05-03 12:10:10 |   18 |
|  3 | 趙敏         | 2017-05-03 14:10:10 |   17 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)
  • create_time 和 id 組合排序
[email protected] [glon_ho]>select * from glon ORDER BY create_time,id limit 0, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  1 | Eason Chan   | 2017-05-02 08:10:10 |   19 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  5 | 周芷若       | 2017-05-02 14:00:00 |   16 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time,id limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
|  7 | 至尊寶    | 2017-05-02 14:00:00 |   20 |
|  8 | 劉三姐    | 2017-05-02 14:00:00 |   19 |
|  2 | Glon Ho   | 2017-05-03 12:10:10 |   18 |
|  3 | 趙敏      | 2017-05-03 14:10:10 |   17 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)
  • 主鍵 id 排序
[email protected] [glon_ho]>select * from glon ORDER BY id limit 0, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  1 | Eason Chan   | 2017-05-02 08:10:10 |   19 |
|  2 | Glon Ho      | 2017-05-03 12:10:10 |   18 |
|  3 | 趙敏         | 2017-05-03 14:10:10 |   17 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY id limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
|  5 | 周芷若    | 2017-05-02 14:00:00 |   16 |
|  6 | Andy Lau  | 2017-05-02 14:00:00 |   50 |
|  7 | 至尊寶    | 2017-05-02 14:00:00 |   20 |
|  8 | 劉三姐    | 2017-05-02 14:00:00 |   19 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)

看到,後面的幾組排序方式都沒有再出現問題了,結合官檔,我們知道 order by 排序的時候,如果排序欄位中有多行相同的列值,則排序結果是不確定的。所以後面的幾組組合形式的排序或者是主鍵 id 的排序,因為唯一性高,所以排序是確定的,不會出現結果混亂的問題。

那是不是可以就此結束了呢,no way, 我們再來看下面的實驗,繼續鞏固一下:

  • 根據年齡 age 來排序:
[email protected] [glon_ho]>select * from glon ORDER BY age limit 0, 4;
+----+------------+---------------------+------+
| id | name       | create_time         | age  |
+----+------------+---------------------+------+
|  5 | 周芷若     | 2017-05-02 14:00:00 |   16 |
|  3 | 趙敏       | 2017-05-03 14:10:10 |   17 |
|  2 | Glon Ho    | 2017-05-03 12:10:10 |   18 |
|  1 | Eason Chan | 2017-05-02 08:10:10 |   19 |
+----+------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY age limit 4, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  8 | 劉三姐       | 2017-05-02 14:00:00 |   19 |
|  7 | 至尊寶       | 2017-05-02 14:00:00 |   20 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

咦,這個排序也只是根據一個欄位 age 來排序,怎麼就沒有出問題呢?不急,還有招:

[email protected] [glon_ho]>insert into glon values (9,'喬峰','2017-05-03 13:10:10',22),(10,'段譽','2017-05-03 15:10:10',19),(11,'郭靖','2017-05-03 17:10:10',20),(12,'黃蓉','2017-05-03 08:10:10',19);
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

[email protected] [glon_ho]>select * from glon;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  1 | Eason Chan   | 2017-05-02 08:10:10 |   19 |
|  2 | Glon Ho      | 2017-05-03 12:10:10 |   18 |
|  3 | 趙敏         | 2017-05-03 14:10:10 |   17 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  5 | 周芷若       | 2017-05-02 14:00:00 |   16 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
|  7 | 至尊寶       | 2017-05-02 14:00:00 |   20 |
|  8 | 劉三姐       | 2017-05-02 14:00:00 |   19 |
|  9 | 喬峰         | 2017-05-03 13:10:10 |   22 |
| 10 | 段譽         | 2017-05-03 15:10:10 |   19 |
| 11 | 郭靖         | 2017-05-03 17:10:10 |   20 |
| 12 | 黃蓉         | 2017-05-03 08:10:10 |   19 |
+----+--------------+---------------------+------+
12 rows in set (0.00 sec)

我又給 glon 表新增了幾條資料,然後再來看看:

[email protected] [glon_ho]>select * from glon ORDER BY create_time limit 0, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  1 | Eason Chan   | 2017-05-02 08:10:10 |   19 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  5 | 周芷若       | 2017-05-02 14:00:00 |   16 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
|  7 | 至尊寶    | 2017-05-02 14:00:00 |   20 |
|  8 | 劉三姐    | 2017-05-02 14:00:00 |   19 |
| 12 | 黃蓉      | 2017-05-03 08:10:10 |   19 |
|  2 | Glon Ho   | 2017-05-03 12:10:10 |   18 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time limit 8, 4;
+----+--------+---------------------+------+
| id | name   | create_time         | age  |
+----+--------+---------------------+------+
|  9 | 喬峰   | 2017-05-03 13:10:10 |   22 |
|  3 | 趙敏   | 2017-05-03 14:10:10 |   17 |
| 10 | 段譽   | 2017-05-03 15:10:10 |   19 |
| 11 | 郭靖   | 2017-05-03 17:10:10 |   20 |
+----+--------+---------------------+------+
4 rows in set (0.00 sec)

根據 create_time 排序,沒有問題了,再來:

[email protected] [glon_ho]>select * from glon ORDER BY age limit 0, 4;
+----+------------+---------------------+------+
| id | name       | create_time         | age  |
+----+------------+---------------------+------+
|  5 | 周芷若     | 2017-05-02 14:00:00 |   16 |
|  3 | 趙敏       | 2017-05-03 14:10:10 |   17 |
|  2 | Glon Ho    | 2017-05-03 12:10:10 |   18 |
|  1 | Eason Chan | 2017-05-02 08:10:10 |   19 |
+----+------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY age limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
| 12 | 黃蓉      | 2017-05-03 08:10:10 |   19 |
| 10 | 段譽      | 2017-05-03 15:10:10 |   19 |
|  8 | 劉三姐    | 2017-05-02 14:00:00 |   19 |
|  7 | 至尊寶    | 2017-05-02 14:00:00 |   20 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY age limit 8, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  7 | 至尊寶       | 2017-05-02 14:00:00 |   20 |
|  9 | 喬峰         | 2017-05-03 13:10:10 |   22 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

可以看到根據年齡 age 排序,問題出現了。

然後在看看組合的排序:

[email protected] [glon_ho]>select * from glon ORDER BY create_time,id limit 0, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
|  1 | Eason Chan   | 2017-05-02 08:10:10 |   19 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  5 | 周芷若       | 2017-05-02 14:00:00 |   16 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time,id limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
|  7 | 至尊寶    | 2017-05-02 14:00:00 |   20 |
|  8 | 劉三姐    | 2017-05-02 14:00:00 |   19 |
| 12 | 黃蓉      | 2017-05-03 08:10:10 |   19 |
|  2 | Glon Ho   | 2017-05-03 12:10:10 |   18 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon ORDER BY create_time,id limit 8, 4;
+----+--------+---------------------+------+
| id | name   | create_time         | age  |
+----+--------+---------------------+------+
|  9 | 喬峰   | 2017-05-03 13:10:10 |   22 |
|  3 | 趙敏   | 2017-05-03 14:10:10 |   17 |
| 10 | 段譽   | 2017-05-03 15:10:10 |   19 |
| 11 | 郭靖   | 2017-05-03 17:10:10 |   20 |
+----+--------+---------------------+------+
4 rows in set (0.00 sec)

[email protected] [glon_ho]>select * from glon