前言

之前我踩过一个order by + limit的坑,最近发现有另外一个同事也踩坑了,现在拿出来跟大家分享一下。

1 背景

我之前提供过一个品牌的分页查询接口,该接口支持按品牌名称模糊搜索。

由于品牌的数据很多,用户输入关键字之后,有可能搜索出很多满足条件的品牌数据。

比如输入关键字:苏三,可能搜索出这样的数据:

苏三说技术

苏三说

我是苏三

苏三的知识星球

苏三

苏三的公众号

球主苏三

...

产品提了一个需求,把匹配度最高的显示到前面。

为了实现产品的需求,我使用了char_length()函数。

sql改成类似这样的:

select * from brand
where name like '%苏三%'
order by char_length(name)
limit 0,20

增加了按名称长度升序的功能,这样可以保证返回的数据是这样的:

苏三

苏三说

我是苏三

球主苏三

苏三说技术

苏三的公众号

苏三的知识星球

...

匹配度最高的排到最前面。

但也却带来了另外一个问题,分页出现了重复的数据,第一页有某某数据,第二页也有某某数据。

为什么会出现这么神奇的现象呢?

2 排序

在mysql中order by关键字是给sql语句排序。

如果你不加order by,mysql默认按主键排序。

但如果你加了order by,同时后面的排序字段出现了重复的数据,mysql对相同的数据的排序是随机的。

order by char_length(name) 使用品牌名称长度升序,而品牌名称的长度有可能出现相同的情况,比如:我是苏三和球主苏三。

如果没有用limit做分页,一次性查询所有的数据,数据只是顺序稍微有点不一样,返回的记录条数和结果没有问题。

但如果这时用limit做了分页,就可能会出现问题。 我是苏三,有可能在第一次查询的时候,在第一页出现了,在第二次查询的时候,却出现在了第二页。

那么,如何解决问题呢?

3 如何解决问题

上面的order by + limit 出现了数据重复的问题。

其根本原因是order by后面的字段,出现了重复的数据。示例中使用了char_length(name),出现了相同长度的品牌名称。

有没有办法将排序结果固定呢?

答:可以增加排序字段。

我们可以在order by后面增加id,即主键排序。

select * from brand
where name like '%苏三%'
order by char_length(name),id
limit 0,20

先按品牌名称长度排序,如果名称长度相同,再按主键排序。

这样可以保证每次order by的排序结果是一样的,不会出现随机排序的情况。

order by + limit的问题,我们在实际工作中,遇到的概率很大,大家一定要引起足够的重视。

最后修改:2026 年 06 月 06 日
如果觉得我的文章对你有用,请随意赞赏