mysql order by值相同_MySQL中order by 与 limit 同用会查出重复的数据

本文探讨了在MySQL中使用ORDER BY和LIMIT进行分页查询时出现的不确定性问题。当ORDER BY的字段存在重复值时,不同页码可能会返回相同的行。官方文档表明,MySQL会对LIMIT进行优化,导致分页结果不准确。解决方案包括使用加索引的唯一字段或结合ROW_NUMBER()函数。实验结果显示,对于区分度不高的字段如时间戳,加索引可能不是最佳策略,应考虑其他优化方法。
摘要由CSDN通过智能技术生成

结论:

如果多行在列中具有相同的值ORDER BY,则服务器可以自由以任何顺序返回这些行,并且根据整体执行计划,这样做的方式可能有所不同。换句话说,这些行的排序顺序相对于无序列是不确定的。

验证:

建表语句:

CREATE TABLE`test_limit` (

`id`int(11) NOT NULLAUTO_INCREMENT,

`name`varchar(45) DEFAULT NULL,

`create_time`datetime DEFAULT NULL,PRIMARY KEY(`id`)

) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8mb4

现在想根据创建时间升序查询test_limit表,并且分页查询,每页3条,那很容易写出sql为:

select * from test_limit order by create_time limit 0,3

执行查询(问题复现):

1、查询第1页数据时:

00b83ac778101c74bf02fbb61111a6a1.png

2、查询第6页数据时:

e5f836b7d7a0e6f127c7a7287e77416d.png

test_limit表共有50条数据,有17页数据,但是实际查询过程中第2页与第6页竟然出现了相同的数据。

上面的实际执行结果已经证明现实与想像往往是有差距的,实际SQL执行时并不是按照上述方式执行的。这里其实是Mysql会对Limit做优化,具体优化方式见官方文档:

这个是5.7版本的说明,提取几个问题直接相关的点做下说明。

8ca695e2b9c5e1e74013c80c0e7cade5.png

翻译:

11b42517303358e2cb2d8e6561c7baf9.png

这里我们查看下对应SQL的执行计划:

93ec64fa64df7ef030461cac6481ae02.png

可以确认是用的文件排序,表确实也没有加额外的索引。所以我们可以确定这个SQL执行时是会找到limit要求的行后立马返回查询结果的。

不过就算它立马返回,为什么分页会不准呢?

官方文档里面做了如下说明:

20b781d3adb1b62044ff40d88bf860ab.png

翻译:

ad3a93ff04c96ecdba4009654feec8a6.png

基于这个我们就基本知道为什么分页会不准了,因为我们排序的字段是create_time,正好又有几个相同的值的行,在实际执行时返回结果对应的行的顺序是不确定的。对应上面的情况,第2页返回的name为a4的数据行,可能正好排在前面,而第6页查询时name为a4的数据行正好排在后面,所以第6页的数据又出现了。

解决:

官方给出的解决方案(推荐):

6a39900273479c195b66019f8d0f9d9b.png

翻译:

cda19d8f2a27bc32d6c946694a19ce90.png

方案二(个人版):

加索引

*对于区分度不高的字段并不推荐,例如add_time,但是update_time还凑合

71ec98011533da4755909bfb980b807e.png

效果验证:

b95921fbb1de51769bdb16a54a8f3584.png

执行计划:

317bb8c1f7520acc8add377e4c99973d.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值