一.问题背景
最近在开发项目的时候,遇到了一个比较棘手的排序问题,在我的订单列表中查看我的订单,产品要求按照先按照等级进行排序,等级相同的情况下,按照时间倒序进行排序。
假设表数据部分字段如下:
id,pin,type,cerat_time
其中pin上建了索引,type表示订单的类型(已提交,已使用,已取消,已退款)等,暂定这四种状态。看到这里,大家肯定想,按照简单的排序不久行了,如下:
select id,type,create_time where pin = #{pin} order by type ,create_time desc
对吧,很简单吧。但是需求是已提交=已使用>已取消=已退款,并且订单创建的时间并不是顺序的,是打乱的,这时候应该怎么办?
二、解决办法
1 集合排序
首先想到的就是,全部都查出来,然后在JVM内存里面进行集合排序操作,看起来很符合逻辑,但是深入一思考,因为这个涉及到数据库的分页操作,如果这么做,你需要每次都把数据都取出来放在内存中操作,然后在进行集合截取,有点太麻烦了,并且,这种方法随着数据量的增加,性能消耗非常大,所以这种方案不合适。
2 添加字段
在数据表中加一个字段,字段表示业务规定的级别,然后利用数据库的排序语句就行,其实这种方案短期来说,应该算合适的方案,并且随着数据量的增大,在性能方面也还可以扛得住,但是唯一的缺点就是拓展性比较差,如果产品给你重新定一种顺序你就傻了,除非你重新刷历史数据,更新你这个字段的值,刷数据有点小麻烦,但是这种方案是可行的哈。
3 sql语句解决
第二种方法相当于采取了一种曲线的方式去解决,那么能不能用sql去直接按照这种规则去排序呢,虽然说看起来有点复杂,但肯定是有的,它就是 CASE WHEN
CASE WHEN type in (1,2)
THEN 1
WHEN type in (3,4)
THEN 2
ELSE 3 END type_copy
这SQL语句的意思就是什么呢,当type为1和2的时候,认为是1等级,当type为3和4的时候,认为是2等级,然后按照这个进行排序不久可以了嘛,如果需求要换,你把这个表达式给改一下不就得了嘛,对吧。
CASE WHEN THEN 简单点说,就像单于if else语句嘛,不同的情况进行不同的赋值,那么完整的SQL语句如下:
SELECT * FROM
(SELECT id,type,create_time,
CASE WHEN type in (1,2)
THEN 1
WHEN type in (3,4)
THEN 2
ELSE 3 END type_copy
from table_name)
where pin=#{pin} order by type_copy,create_time desc limit 0,10;
三 问题延伸
但是,这还是有个问题,如果数据量超过千万,这会不会造成数据库慢查,形成性能瓶颈,并且这种直接面向客户的话,如果高并发,直接捞库肯定是不行,容易直接崩(目前项目数据量和并发不大,方案并不考虑这个方面),这种情况,放在Redis中把,也不是太合适,存起来不太好存。
最后考虑,可以把数据放在ES进行操作,利用ES的聚合能力进行排序,应该很容易的解决,
但是这还得考虑数据量大小,如果数据量几十万左右还是不要用ES,性能和Mysql差不太多,还麻烦,当数据量达到百万级别的规模上,就需要考虑ES了!
网友评论