解决 MySQL 分页数据错乱重复

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 解决 MySQL 分页数据错乱重复

前言

一天,小明很着急地在通讯工具上说:这边线上出现了个奇怪的问题,麻烦 DBA 大大鉴定下,执行语句 select xx from table_name wheere xxx order by 字段A limit offset;

表数据总共 48 条,分页数量正常,但出现了结果混杂的情况,第一页的数据出现在了第二页上;如果 order by 字段B 就不会出现这个现象,怎么会这样呢!

其实,这个问题很简单,如果你有仔细阅读官档的话。~^_^~

我们先来看看官档是怎么说的:

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~),下面先创建实验环境和初始化测试数据:

root@localhost [(none)]>select @@version;
+------------+
| @@version  |
+------------+
| 5.6.26-log |
+------------+
1 row in set (0.00 sec)
root@localhost [(none)]>show variables like "sql_mode";
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| sql_mode      | NO_ENGINE_SUBSTITUTION |
+---------------+------------------------+
1 row in set (0.00 sec)
root@localhost [(none)]>create database glon_ho;
Query OK, 1 row affected (0.04 sec)
root@localhost [(none)]>use glon_ho
Database changed
root@localhost [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)
root@localhost [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
root@localhost [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 来排序:
root@localhost [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)
root@localhost [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 组合排序
root@localhost [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)
root@localhost [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 组合排序
root@localhost [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)
root@localhost [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 排序
root@localhost [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)
root@localhost [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 来排序:
root@localhost [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)
root@localhost [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 来排序,怎么就没有出问题呢?不急,还有招:

root@localhost [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
root@localhost [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 表新增了几条数据,然后再来看看:

root@localhost [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)
root@localhost [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)
root@localhost [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 排序,没有问题了,再来:

root@localhost [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)
root@localhost [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)
root@localhost [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 排序,问题出现了。

然后在看看组合的排序:

root@localhost [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)
root@localhost [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)
root@localhost [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)
root@localhost [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)
root@localhost [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 |
| 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)
root@localhost [glon_ho]>select * from glon ORDER BY create_time,age 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)
root@localhost [glon_ho]>select * from glon ORDER BY age,id 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)
root@localhost [glon_ho]>select * from glon ORDER BY age,id limit 4, 4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
|  8 | 刘三姐    | 2017-05-02 14:00:00 |   19 |
| 10 | 段誉      | 2017-05-03 15:10:10 |   19 |
| 12 | 黄蓉      | 2017-05-03 08:10:10 |   19 |
|  7 | 至尊宝    | 2017-05-02 14:00:00 |   20 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)
root@localhost [glon_ho]>select * from glon ORDER BY age,id limit 8, 4;
+----+--------------+---------------------+------+
| id | name         | create_time         | age  |
+----+--------------+---------------------+------+
| 11 | 郭靖         | 2017-05-03 17:10:10 |   20 |
|  4 | Jacky Cheung | 2017-05-02 14:00:00 |   22 |
|  9 | 乔峰         | 2017-05-03 13:10:10 |   22 |
|  6 | Andy Lau     | 2017-05-02 14:00:00 |   50 |
+----+--------------+---------------------+------+
4 rows in set (0.00 sec)

思考

既然排序不定,那么给排序字段加上索引会不会有用呢?

root@localhost [glon_ho]>alter table glon add index ix_age(age);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0
root@localhost [glon_ho]>show create table glon\G
*************************** 1. row ***************************
       Table: glon
Create Table: CREATE TABLE `glon` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `create_time` datetime NOT NULL,
  `age` tinyint(3) unsigned DEFAULT '18',
  PRIMARY KEY (`id`),
  KEY `ix_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
root@localhost [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)
root@localhost [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)
root@localhost [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)

也可以不在 order by 后面加多一列增加唯一性,可以改写成下面的形式:

root@localhost [glon_ho]>select * from (select distinct g.* from glon g order by age) t 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)
root@localhost [glon_ho]>select * from (select distinct g.* from glon g order by age) t limit 4,4;
+----+-----------+---------------------+------+
| id | name      | create_time         | age  |
+----+-----------+---------------------+------+
| 10 | 段誉      | 2017-05-03 15:10:10 |   19 |
|  8 | 刘三姐    | 2017-05-02 14:00:00 |   19 |
| 12 | 黄蓉      | 2017-05-03 08:10:10 |   19 |
| 11 | 郭靖      | 2017-05-03 17:10:10 |   20 |
+----+-----------+---------------------+------+
4 rows in set (0.00 sec)
root@localhost [glon_ho]>select * from (select distinct g.* from glon g order by age) t 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)

总之,如果发生了,最简单的方法就是在排序列(如 create time)上加索引,然后在 order by 上明示 primary key,这个问题就非常圆满的解决了。

总结

MySQL 使用 limit 进行分页时,可能会出现重复数据,通过加入 order by 子句可以解决,但是需要注意的是,如果排序字段有相同值的情况下,由于排序字段数据重复,可能会导致每次查询排序后结果顺序不同,分页还是会出现重复数据,这时可以加入第二个排序字段,提高排序的唯一性,最好保证排序的字段在表中的值是唯一的,这样就可以少写一个排序字段,增加查询效率,因为 order by 后面有多个排序字段时,无法用到索引。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
26天前
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
146 0
|
7天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
113 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
7天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
40 14
|
10天前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
42 9
|
17天前
|
SQL NoSQL 关系型数据库
2024Mysql And Redis基础与进阶操作系列(5)作者——LJS[含MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页等详解步骤及常见报错问题所对应的解决方法]
MySQL DQL基本查询:select;简单、排序、分组、聚合、分组、分页、INSERT INTO SELECT / FROM查询结合精例等详解步骤及常见报错问题所对应的解决方法
|
22天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
18天前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
38 1
|
20天前
|
SQL 关系型数据库 MySQL
mysql数据误删后的数据回滚
【11月更文挑战第1天】本文介绍了四种恢复误删数据的方法:1. 使用事务回滚,通过 `pymysql` 库在 Python 中实现;2. 使用备份恢复,通过 `mysqldump` 命令备份和恢复数据;3. 使用二进制日志恢复,通过 `mysqlbinlog` 工具恢复特定位置的事件;4. 使用延迟复制从副本恢复,通过停止和重启从库复制来恢复数据。每种方法都有详细的步骤和示例代码。
|
分布式计算 关系型数据库 MySQL
E-Mapreduce如何处理RDS的数据
目前网站的一些业务数据存在了数据库中,这些数据往往需要做进一步的分析,如:需要跟一些日志数据关联分析,或者需要进行一些如机器学习的分析。在阿里云上,目前E-Mapreduce可以满足这类进一步分析的需求。
4971 0
|
9天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
23 4