【Mysql】Mysql排序的字段值重复时导致分页查询数据错乱的问题解决

文章介绍了在MySQL中,当ORDERBY的字段存在重复值时,分页查询可能出现错乱的问题。原因是服务器对具有相同排序值的行返回顺序是不确定的。解决方案包括为排序字段添加索引或在ORDERBY子句中加入具有唯一性的列,如ID,以确保查询的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 问题描述

今天发现一个系统Bug,原来页面中的分页查询错乱了,经过排查发现,是因为排序的字段存在重复值引起的。

例如:

idnameage
1张三23
2李四23
3小明23
20李华23

当我们分别执行

# 第1到10行数据
select * from user_table order by age limit 0,10
# 第11到20行数据
select * from user_table order by age limit 10,10

我们会发现第一次查询的数据再第二次中出现(非必然,这里只是举例,我遇到的错乱问题描述)。

2. 原因

官网描述:https://dev.mysql.com/doc/refman/8.0/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 列中具有相同的值,则服务器可以自由地以任何顺序返回这些行,并且可能会根据整体执行计划以不同的方式返回这些行。换句话说,这些行的排序顺序相对于无序列来说是不确定的。

3. 处理方法

方法一:添加排序字段为索引字段

create index idx_user_age
    on user_table (age);

方法二:在ORDER BY子句中加入具有唯一性的列

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

如果必须确保有 LIMIT 和无 LIMIT 时的行顺序相同,可以在 ORDER BY 子句中加入额外的列,使顺序具有确定性。例如,如果 id 值是唯一的,则可以通过以下排序方式使给定类别值的记录按 id 排序

例如将

select * from user_table order by age limit 0,10

改为

select * from user_table order by age,id limit 0,10
### MySQL分页查询字段相同导致结果重复解决方案 在处理MySQL分页查询,如果存在字段相同的情况,可能会导致结果集中出现重复记录。这种现象通常发生在`LIMIT`语句结合`ORDER BY`使用的情况下[^2]。以下是几种常见的解决方案: #### 1. 使用唯一标识符作为排序依据 通过引入唯一的列(如主键ID),可以有效避免因其他字段相同而导致重复问题。例如,在查询中加入主键列并将其用于排序操作。 ```sql SELECT id, name, value FROM test_table ORDER BY name ASC, id ASC -- 添加id作为辅助排序项 LIMIT 400000, 3; ``` 这种方法能够确保即使某些字段相同,也能基于主键实现稳定的排序顺序。 #### 2. 应用DISTINCT关键字去除重复行 当确实需要排除完全相同的行,可以在查询中应用`DISTINCT`关键字来过滤掉冗余的数据条目。 ```sql SELECT DISTINCT id, name, value FROM test_table ORDER BY name LIMIT 400000, 3; ``` 需要注意的是,虽然`DISTINCT`能帮助消除显式的重复记录,但它可能增加额外的计算开销,并且对于部分复杂的场景未必是最优解法[^1]。 #### 3. 调整子查询逻辑以预处理数据 另一种方式是先执行一次内部查询获取目标范围内的所有候选记录,然后再对外部结果集施加进一步约束条件或者再次筛选不必要项目。 ```sql EXPLAIN SELECT SQL_NO_CACHE * FROM emp INNER JOIN ( SELECT id FROM emp e ORDER BY deptno , id -- 增加id保证稳定性 LIMIT 10000, 40 ) a ON a.id = emp.id ; ``` 上述例子展示了如何构建嵌套结构从而精确控制最终返回的内容集合。 #### 4. 设计合理的索引提升性能表现 针对频繁访问的大规模表格实施恰当索引创建策略同样重要。合理配置覆盖索引不仅有助于加速检索过程而且还能减少临文件生成概率进而改善整体效率水平[^3]。 另外得注意的一点在于大规模分布式环境下单纯依靠传统关系型数据库难以满足高效需求,则考虑采用专门化工具譬如NoSQL存储引擎(MongoDB/Redis),大数据平台(Hadoop/HBase/Solr/Elasticsearch)以及相应框架(MapReduce)[^3]. 综上所述,面对此类挑战可综合运用多种手段加以应对,既包括调整现有SQL语法又涉及改进基础设施布局等方面工作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫巳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值