背景
如题,最近在实践中需要存储大量聊天数据,但是在处理数据分页的时候遇到了一些阻力
环境与当前的逻辑
环境
部分技术选型如下:
版本 | |
---|---|
Java | 21 |
SpringBoot | 3.4.3 |
mybatis | 3.0.4 |
使用MySQL 8.0.41为主数据库,Redis做缓存,java+服务端+redis统一封装进docker部署
插入/查询逻辑
要求是做群的聊天记录存储就可以了
当前的群号为一串数字如:87324986948
由于是大量聊天记录,于是分表,分为了N
张表,表名为group_message_N
每个群的消息通过简单的取模平均分配在各个表中,部分代码如下:
public GroupMessage selectGroupMessageById(Long groupId, Long groupMessageId, Integer groupType) {
String tableSuffix = String.valueOf(groupId % 64);
return groupMessageMapper.selectMessageById(
tableSuffix,
groupType,
groupMessageId,
groupId
);
}
表的Column如下:
Key | 类型 | 描述 |
---|---|---|
message_id | BIGINT | 消息ID (出于历史原因,message_id是无序的) |
group_id | BIGINT | 群组ID |
group_type | INT | 群组类型 |
user_id | BIGINT | 用户ID(发送者ID) |
type | INT | 消息类型 |
content | JSON | 消息内容 |
create_time | BIGINT | 发送时间 |
索引如下:
问题
后端返回数据肯定是要分页的
所有群挤在一起不能用primary key
没有针对某个群的自增message_id,message_id是无序的也不能用来做游标
于是现在使用的是时间游标分页,具体查询sql如下:
<select id="getMessageCountAfterDate" resultType="Long">
<![CDATA[
SELECT COUNT(*)
FROM group_message_${tableSuffix} FORCE INDEX (idx_group_create_time)
WHERE group_id = #{groupId} AND group_type = #{groupType} AND create_time >= #{startDate};
]]>
</select>
在这种情况下,如何快速查询某页的消息
每页消息数pageSize
和页数page
都是不固定的,第一页始终是最新的消息,所以也不能直接缓存每页的游标
如果直接使用SELECT LIMIT
,在大量数据的情况下效率会很低
请问各位在不修改表的情况下有没有更优解?