自定义排序方案

799 阅读2分钟

    这段时间遇到一个需求,就是对列表数据进行自定义排序。一开始的想法是数据库中增加一个排序字段,比如:

idnamesort_num
1张三1
2李四2
.........
1000王五1000

    当要调整选项的顺序时,则调整对应选项的sort_num。但这样有个问题,就是修改很慢。比如要把id为1000条数据的排序放在最前面,就首先需要把他的sort_num改为1,然后把id为1到999的所有数据的sort_num依次加1。

    后面我们对上面做了一点改进。在存储sort_num时不再是加1,而是增加一个固定步长,当需要移动排序时,新的sort_num取目标位置相邻两个数的中间值。假设上述数据我们设置固定步长为1024,则变为:

idnamesort_num
1张三1024
2李四2048
.........
1000王五1024000

    现在移动的方案变成以下方式:

    1.如果要把id为1000的数据移动到第2位。目标位置相邻的两个数据sort_num分别为1024和2048,则将id为1000的数据的sort_num改为1024 + (2048 - 1024) / 2 = 1536。

    2.如果再把id为999的数据移动到第2位。将id为999的数据的sort_num改为1024 + (1536 - 2014) / 2 = 1280。

...

    经过10次后第1位和第2位数之间的sort_num变为1024和1025,两个数据之间的间隔只相差1,此时不能再插入数据了。此时需要做一次全局调整,将所有的sort_num恢复到初始值。这样每一个位置上最大可以不断移动10次,这就大大减少了批量移动的次数。

    恢复初始值SQL示例:

update table_name t, (select @rownum:=@rownum+1 rownum,table_name.* from table_name, (select @rownum := 0) tmp order by sort_num) i set t.sort_num =i.rownum where t.id = i.id;

    在整个过程中需要做好边界条件的判断,首尾都要有个挡板数据,首部挡板数据可以设置为0,尾部可以设置为(count(*) + 1) *1024。

    以上方案在数据量比较大的情况下不太适用,不过通常情况下有这种需求的数据通常不会太大。