对于上移下移业务,比如现在对工作任务进行排序,表设计一般如下:
create table "task" (
id varchar
task_name varchar // 任务名称
order_num int // 排序值
);
原始实现思路
- 插入到最后:找出最大的orderNum,然后新增的item的orderNum为maxOderNumber+1
- 插入到中间:找出要插入的前一个item,然后在排在这个item后的的所有item,将他们的orderNum+1,往后挪,最后在插入新增的item。这样子会导致,要往后挪orderNum数据会很多,效率很慢。
- 删除:删除item,然后找出排在该item后的所有item,往前挪。这样子会导致,要往前挪orderNum数据会很多,效率很慢。
- 上移/下移:找到要上移item的orderNum,然后根据orderNum-1找到前一个item,互换orderNum。如果是代码写死根据orderNum-1来找到前一个item,这样子对数据要求很高,oderNumber必须要是连续的,如果出现脏数据排序会失效!
改良实现思路
原始实现思路一的最大缺点有2个
- 插入到中间,或者删除中间的元素,往后挪和往前挪的数据会非常多,影响效率
- 上移下移如果根据orderNum-1或orderNum+1来找前一个或后一个item,这样子对数据的要求会很高,必须要求orderNum是连续+1递增的。
- 也是正因为对数据的要求高,所以插入和删除的时候不得不维护其他item的orderNum
改良实现思路
- 插入(如插入item的Id,前一个preItem的id)
第一步:找出前一个item的orderNum,select orderNum where id = preItem.id,没有则默认为0
第二步:找出前一个item的后一个item的orderNum,select orderNum from task where orderNum > preItem.orderNum order by orderNum asc limit 1
第三步:新插入item的orderNum = (suffixItem.orderNum - preffixItem.orderNum) / 2,在保留x位小数。具体数据库是用double还是varchar存储,这个笔者还没研究哪个效率比较高。 - 删除(要删除的itemId)
直接删除item,不需要挪动任何其他的item - 上移/下移(要上移的itemId)
第一步:找到要上移item的orderNum
第二步:找出要上移item的前一个item的orderNum,select orderNum from task where orderNum < item.orderNum order by orderNum asc limit 1
第三步:如果前一个oderNum不存在,则表示当前item在最上了,无法移动
第四步:否则将这两个item交换orderNum,保存
第五步:可以在开启一个定时器,定时整理orderNum的值
总结:改良实现思路的好处是解决了两个问题
1.通过where order > xxx limit 1来找出前一个或后一个,而不是通过order+1或order-1来找出前一个或后一个,可以降低对数据的要求,不要求order必须是连续递增+1的。
2.正因为对数据的要求降低了,所以删除和插入不需要维护其他item的orderNum了,所以也就加快删除和插入的效率了!