正确的Redis数据类型,让访问时间提高几十倍

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

问题背景

接到了一个需求,是通过物品查询分类中涨价排行最高的N个子类,再查询每个子类对应的涨价排行最高的N个物品。由于数据结构是hash类型,全部物品、子类物品-价格、物品-子类、子类排行。
看到了物品对应子类集合和子类-价格集合,通过取交集,能将物品对应的子类排行查出来,尝试使用redis的zset来实现。

但是并发量上来之后,发现redis取交集这个操作很耗时。于是用hash结构保存数据,再用java进行排序,代码多了好几行,但是并发查询的时间大幅度缩短。

Redis的数据类型可参考: # 【简约入门】Redis的数据类型及常用命令https

原始代码

1
2
3
4
5
6
java复制代码	// 取goods与category的交集,结果放到result中		
redisTemplate.opsForZSet().intersectAndStore(goods,category,result);
int start = (pageNum-1) * pageSize;
// 分页获取集合
Set<ZSetOperations.TypedTuple<Object>> rangeWithScores = redisTemplate.opsForZSet().reverseRangeWithScores(result, start, pageSize - 1);
System.out.println(rangeWithScores);

优化后代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
java复制代码        // 查询goodId对应的类别
List<Object> categoryList = (List<Object>) redisHash.hGet("good:categorys",goodId);
// 查询上面查出类别的价格
List idxPriceList = redisHash.multiGet("category",categoryList);

List<Map> idxList = new ArrayList<>();
for (int i = 0;i<boardList.size();i++){
Map<String, Object> idxM = new HashMap<>();
idxM.put("k",boardList.get(i));
idxM.put("v",idxPriceList.get(i));
idxList.add(idxM);
}
// 种类按价格排序
idxList.sort((o1, o2) -> {
return (o1.get("v").toString()).compareTo(o2.get("v").toString());
});
System.out.println(idxList);
// 获取最高物品的代码
String code = idxList.get(0).get("k").toString();
// 种类下的物品
List<Object> sList = (List<Object>) redisHash.hGet("category:goods",code);

// 查找物品对应价格
List codeList = redisHash.multiGet("good:price",sList);

List<Map> codeIdxList = new ArrayList<>();
for (int i = 0;i<sList.size();i++){
Map<String, Object> idxM = new HashMap<>();
if(null != codeList.get(i)){
idxM.put("k",sList.get(i));
idxM.put("v",codeList.get(i));
codeIdxList.add(idxM);
}
}

// 按价格排序
codeIdxList.sort((o1, o2) -> {
return (o1.get("v").toString()).compareTo(o2.get("v").toString());
});
// 分页获取数据
codeIdxList = codeIdxList.stream().limit(pageSize).collect(Collectors.toList());

System.out.println(codeIdxList);

小结

当并发30、50的时候,使用redisTemplate.opsForZSet().intersectAndStore取交集的平均耗时是超过500ms的,并且尝试使用spring注解,加载多个redisTemplate来取交集,发现每个执行时间还是一样,如果只是取交集还可以,由于数据结构复杂需要多个交集操作,多个查询操作,使得整体的查询时间很长,2-3s。

改变java代码排序,取出最高的种类,再取出这个种类下的物品,效率更高,查询结果可控制在100ms左右。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%