您查询的关键词是:最代码 
下面是原始网址 http://www.zuidaima.com/share/2639239673302016.htm 在 2018-03-08 09:07:49 的快照。

360搜索与该网页作者无关,不对其内容负责。

最代码网站用户私信列表采用mysql union查询优化为Redis查询的经验和相关代码片段分享-分享-最代码
最代码官方的gravatar头像
最代码官方2015-12-12 19:56:20

最代码网站用户私信列表采用mysql union查询优化为Redis查询的经验和相关代码片段分享

由于用户和私信的数据量逐渐增加,查询用户和其他用户的私信合并排重排序的sql语法给mysql带来了很大的压力,springdata jpa的hql查询语法如下:

select id from (select id,target_id,case when user_id=?1 and type=?2 then 'sender' else 'receiver' end flag from javaniu_post where user_id=?1 and type=?2 union select id,user_id,case when user_id=?1 then 'sender' else 'receiver' end flag from javaniu_post where target_id=?1 and type=?2 order by id desc) as ret group by target_id order by id desc

在mysql的slow查询中经常会出现10s以上的记录:

最代码网站用户私信列表采用mysql union查询优化为Redis查询的经验和相关代码片段分享

mysql查询性能的瓶颈在于某个用户和其他用户之间交互越多,发送私信越多,mysql union查询参与运算的集合数据量会越大,性能也会越来越低。

数据变化如下:

1.用户A发给用户B生成私信1

用户A->用户B->私信1

2.用户A发给用户C生成私信2

用户A->用户C->私信2

3.用户A发给用户E生成私信3

用户A->用户E->私信3

4.查询用户A的私信列表

私信3,私信2,私信1

5.用户B发给用户A生成私信4

用户B->用户A->私信4

6.查询用户A的私信列表

私信4,私信3,私信2

私信1因为有最新数据私信4的存在,所以不会返回。

所以迫切需要引入新的技术来解决该查询的性能瓶颈,想到了流行的redis技术,于是修改设计如下:

模拟发私信的数据结构如下

127.0.0.1:6379> zadd uid1 1 2
(integer) 1
127.0.0.1:6379> zadd uid1 2 3
(integer) 1
127.0.0.1:6379> zadd uid1 3 5
(integer) 1
127.0.0.1:6379> zrevrange uid1 0 -1
1) "5"
2) "3"
3) "2"
127.0.0.1:6379> zrevrange uid1 0 -1 withscores
1) "5"
2) "3"
3) "3"
4) "2"
5) "2"
6) "1"
127.0.0.1:6379> zadd uid1 4 2
(integer) 0
127.0.0.1:6379> zrevrange uid1 0 -1 withscores
1) "2"
2) "4"
3) "5"
4) "3"
5) "3"
6) "2"
127.0.0.1:6379>

注意:把私信id做为score来做排序

相关代码片段如下:

删除或添加私信时:

String uid = t.getUserId() + "";
String type = ModuleConstants.POST_TYPE_MESSAGE + "";
String tgid = t.getTargetId() + "";
long id = t.getId();
long time = t.getCreateTime().getTime();
String po_uid_tp_tgid = String.format(
RedisConstants.POST_USERID_TYPE_TARGETID, uid, type, tgid);
// from uid
String po_uid_tp = String.format(RedisConstants.POST_USERID_TYPE,
uid, type);
// to uid
String po_tgid_tp = String.format(RedisConstants.POST_USERID_TYPE,
tgid, type);
if (t.getStatus() == ModuleConstants.MODULE_STATUS_DELETED) {// 删除私信同时要删除redis
zsetOps.remove(po_uid_tp_tgid, id + "");
zsetOps.remove(po_uid_tp, tgid);
zsetOps.remove(po_tgid_tp, uid);
} else {
zsetOps.add(po_uid_tp_tgid, id + "", time);
zsetOps.add(po_uid_tp, tgid, id);
zsetOps.add(po_tgid_tp, uid, id);
}

查询用户的私信时:

String uid = userId + "";
String tp = ModuleConstants.POST_TYPE_MESSAGE + "";
String po_uid_tp = String.format(RedisConstants.POST_USERID_TYPE, uid,
tp);
int total = zsetOps.zCard(po_uid_tp).intValue();
int ps = total / count + (total % count > 0 ? 1 : 0);
if (page > ps) {
page = ps;
}
int start = (page - 1) * count;
int end = page * count - 1;
Set<TypedTuple<String>> _ids = zsetOps.reverseRangeWithScores(
po_uid_tp, start, end);
List<Long> ids = new ArrayList<Long>();
Iterator<TypedTuple<String>> iterator = _ids.iterator();
while (iterator.hasNext()) {
TypedTuple<String> _id = iterator.next();
long id = _id.getScore().longValue();
ids.add(id);
}
List<Post> ts = (List<Post>) findAllByIds(ids);
Pageable pageable = new PageRequest(page - 1, count);
Page<Post> _page = new PageImpl<Post>(ts, pageable, total);
initBeans(_page.getContent());

redis查询最代码官方,id=1的所有私信列表,和mysql union运算的结果完全一致,但是性能可是天壤之别:

最代码网站用户私信列表采用mysql union查询优化为Redis查询的经验和相关代码片段分享
info的memory截图和keyspace截图

最代码网站用户私信列表采用mysql union查询优化为Redis查询的经验和相关代码片段分享

最代码网站用户私信列表采用mysql union查询优化为Redis查询的经验和相关代码片段分享

相关资料和代码:

mysql sql查询如何实现发私信用户和其他用户的列表?要求消重所有重复的用户结果

最代码网站的私信功能


打赏

>扫描二维码关注<b style='color:black;background-color:#ffff66'>最代码</b>为好友扫描二维码关注最代码为好友