这个问题相信不少人都遇到过,但很少有人追根溯源。今天我抽出一点时间,来讨论讨论 order by + limit 在什么情况下会出现分页数据重复。
昨天在“CTO”群提问了之后,不少大神都回答的相当正确。我这里结合一下他们的回答,并补充一些内容分享给大家!
排序离不开算法,在关系型数据库中,往往会存在多种排序算法。通过 MySQL 的源码和官方文档介绍可以得知,它的排序规律可以总结如下:
- 当 order by 不能使用索引进行排序时,将使用排序算法进行排序;
- 若排序内容能全部放入内存,则仅在内存中使用快速排序;
- 若排序内容不能全部放入内存,则分批次将排好序的内容放入文件,然后将多个文件进行归并排序;
- 若排序中包含 limit 语句,则使用堆排序优化排序过程。
其他如:PG,MariaDB,AliSQL,SQL Server 等排序算法方面差别不大。
根据上面的总结,当你的 order by limit 分页出现数据重复。比如,一个用户表,当使用 limit 5 后出现一个张三。再使用 limit 5,10 的时候,张三又出现了。注意,这两个张三是同一个人,id 是相同的。在这种情况下,你的 order by 肯定是没有使用索引的。因为使用了索引,就会进行索引排序。
根据官方文档显示,以及我上面的总结,可以得出。上面的 SQL 使用了堆排序。因为,category 没索引,所以没走索引排序;其二我们使用了 limit,所以最终使用了堆排序。而了解算法的朋友都知道,堆排序是不稳定的。
比如,我们现在有下面一列数。
为了,看清两个 2 的区别,我分别给它们多标了一个数字。
那么使用堆排序的结果,可能会存在下面的结果。
这种不稳定性,指的就是多次排序后,各个数的相对位置发生了变化。
除了堆排序,不稳定的排序还有下面这些排序算法。
那么如何解决 order by limit 分页数据重复问题呢?方法有多种,我这里列举最常用的两种方法。
第一种就是,在排序中加上唯一值,比如主键 id,这样由于 id 是唯一的,就能确保参与排序的 key 值不相同。
第二种就是避免使用堆排序,让 order by 根据索引来排序。说白了,就是 order by 后面的字段要有索引。
以上,知道的越多,不知道的就越多,业余的就像一棵小草一样!
参考资料:
- https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html
- https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
- https://en.wikipedia.org/wiki/Sorting_algorithm
: » 从根上理解order by limit分页数据重复问题
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/java/252171.html