
# Order by limit分页出现数据重复问题
#### 问题现象
对一个表执行排序，并对排序结果进行分页，得到的结果不符合预期。
假设有一个名为商品(merchants)的表，只有一个商品id和商品种类category两个字段，表结构如下：
```
mysql> show create table merchants;
+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                            |
+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| merchants | CREATE TABLE `merchants` (
  `id` int NOT NULL AUTO_INCREMENT,
  `category` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci |
+-----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```
执行如下SQL，查看表中的内容。
```
mysql>  select * from merchants;
+----+----------+
| id | category |
+----+----------+
|  1 |        1 |
|  2 |        3 |
|  3 |        2 |
|  4 |        2 |
|  5 |        1 |
|  6 |        2 |
|  7 |        3 |
|  8 |        3 |
|  9 |        2 |
| 10 |        1 |
+----+----------+
10 rows in set (0.00 sec)
```
执行如下SQL，对商品按照类别(category)字段进行排序。
```
mysql> select * from merchants order by category;
+----+----------+
| id | category |
+----+----------+
|  1 |        1 |
|  5 |        1 |
| 10 |        1 |
|  3 |        2 |
|  4 |        2 |
|  6 |        2 |
|  9 |        2 |
|  2 |        3 |
|  7 |        3 |
|  8 |        3 |
+----+----------+
10 rows in set (0.00 sec)
```
执行如下SQL，将排序结果用limit分页，每页两行数据。
```
mysql> select * from merchants order by category limit 0,2;
+----+----------+
| id | category |
+----+----------+
|  1 |        1 |
|  5 |        1 |
+----+----------+
2 rows in set (0.00 sec)
 
mysql> select * from merchants order by category limit 2,2;
+----+----------+
| id | category |
+----+----------+
|  1 |        1 |
|  9 |        2 |
+----+----------+
2 rows in set (0.00 sec)
```
可以看到，第二页的数据出现了错误。按照没有分页时的排法，第二页应该显示为id为10和id为3的行，但实际结果这里是id为1和9的行。
#### 原因分析
优化器在遇到order by limit语句的时候，做了一个优化，内部使用priority queue结构做排序，该排序方式属于不稳定排序算法，筛选出limit n的结果后就直接返回，不能保证有序性。
#### 解决方案
- 方案1：可以在需要排序的字段上加上索引。如案例中，alter table ratings add index idx_category (category);
- 方案2：可以在排序语句的order by后面加入主键列。如案例中，select \* from ratings order by category, id limit 2,2;
- 方案3：可以在TaurusDB控制台参数修改页面，开启参数"rds_force_stable_sort"。该参数开启后，将强制使用稳定排序算法，确保排序结果的稳定。
  图1设置参数rds_force_stable_sort   
  ![](https://support.huaweicloud.com/trouble-taurusdb/figure/zh-cn_image_0000002025255697.png) 
 
