问题描述

最近线上出现了一个问题,在某个 SELECT ... FROM table1 ORDER BY ××× LIMIT N 时,第一页和第二页出现了重复的数据。

结论

MySQL在5.6版本的时候对 ORDER BY LIMIT 做了个优化(排序字段无索引,且值不唯一)时,优化器遇到 ORDER BY LIMIT 语句的时候,使用了priority queue(优先队列),优先队列使用的堆排序,因为这种场景是用于求TOP N 问题,堆排快,但是堆排不稳定。

分析

在官方文档当中,有提到 在这里插入图片描述官方文档当中

while (get_next_sortkey())
     {
       if (using priority queue)
         push sort key into queue
       else
       {
         if (no free space in sort_keys buffers)
         {
           sort sort_keys buffer;
           dump sorted sequence to 'tempfile';
           dump BUFFPEK describing sequence location into 'buffpek_pointers';
         }
         put sort key into 'sort_keys';
       }
     }
     if (sort_keys has some elements && dumped at least once)
       sort-dump-dump as above;
     else
       don't sort, leave sort_keys array to be sorted by caller.

描述了伪代码的优化。原因是啥呢,就是因为快。

PQ

priority queue 是一个堆,order by limit 本质上就是在求TOP N ,那只要求出最大N条数据/最小的N条数据就行。剩下的数据不需要再进行排序,这样就极大的加快了速度。而堆排序总所州市

解决办法

1.索引排序字段 在这里插入图片描述 2.在排序中加上唯一值,比如主键 id,这样由于 id 是唯一的,就能确保参与排序的 key 值不相同。

参考文章:

https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html