在使用rocketmq消息中心时,为了保证幂等我专门建了个消息消费记录表,每个消息消费后都往消息消费记录中插一条数据,在消息到达时通过判断是否在消息消费记录中存在这个消息来保证幂等。
但是因为我把很多事件都放到队列中,所以消息的数量是十分之多的,一天能产生几十万条消息,而查询消息消费记录的代码执行频率十分之高,这时候我发现使用select count(*) 的效率急剧下降。我赶紧建了个定时器定时删除过早的消息。这时我想起了主管说过hibernate的exists会在找到第一条消息时就直接返回true,而count则要将表中所有数据遍历后才返回。
于是我起了兴趣尝试使用exists来优化查询
select EXISTS(select id from message_consumer_history where keyCode = ?1 and type = ?2 and listenType=?3 limit 1)
好吧,其实效果和直接select id from message_consumer_history where keyCode = ?1 and type = ?2 and listenType=?3 limit 1
是一样的,关键是limit限制后语句只要找到结果就会返回。值得注意的是limit在count中是无效的。
实际效果并不怎么好,因为如果没有找到消息记录时,还是会将整个表查询一遍,而这种情况才是普遍的。重复消费算是特殊情况。而且一般来说,重复消费的消息是较后插入的,这意味着查询时位置靠后,根本节省不了多少时间。要想加快效率还是及时删除数据或者使用缓存靠谱点。
不过不管怎样还是提高了些微的效率,而且未来应该还是有适用的场景吧