用Redis怎么快速搞定总数统计,查记录数其实挺简单的
- 问答
- 2025-12-31 13:10:34
- 2
说到统计总数,比如一个网站的总用户数、一篇文章的总阅读量、或者一个活动参与的总人数,最直接的想法可能就是去数据库里执行一条 SELECT COUNT(*) FROM table 的 SQL 语句,这个方法在小数据量的时候没问题,但是当数据量变得非常大,比如表里有几千万甚至上亿条记录时,这个 COUNT(*) 操作就会变得非常慢,因为它需要扫描大量的数据行,会对数据库造成很大的压力,影响其他正常业务的性能。
这时候,Redis 就能派上大用场了,它的速度非常快,因为数据都在内存里操作,用 Redis 来做总数统计,核心思想就一句话:把计数的活儿从“计算”变成“查询”,我们不再需要每次临时去数,而是提前把数好的结果存起来,用的时候直接拿出来就行,下面介绍几种最常见、最实用的方法。
第一种方法,也是最好用的:使用 INCR 命令。
这个命令是专门为计数器设计的,它的逻辑非常简单:我给你一个键(key),你每次命令它,它的值就自动加 1,如果这个键不存在,Redis 会先把它初始化为 0,然后再执行加 1 操作。
我们要统计网站的总用户注册数。
- 每当有一个新用户注册成功时,我们在业务代码里就执行一条 Redis 命令:
INCR user:register:count。 - 这样,
user:register:count这个键的值就是当前的总用户数。 - 当我们需要查询总用户数时,只需要执行一条
GET user:register:count命令,瞬间就能得到结果,这个速度和查询一个简单的字符串是一样的,完全不受用户总量多少的影响。
这个方法的好处是:
- 极致速度:写入(INCR)和读取(GET)都是 O(1) 时间复杂度,是常数级别的,快得飞起。
- 绝对准确:因为 INCR 是原子性操作,即使在很高的并发环境下,比如一秒内有上万个用户同时注册,也不会出现计数错误的情况,每个用户都会被精确地统计一次。
根据 Redis 官方文档中对 INCR 命令的描述,它就是用于这种计数器场景的原子操作,对于这种只需要一个总和的计数需求,INCR 是首选方案。
第二种方法,适用于需要按维度统计的:使用哈希(Hash)。
有时候我们的统计需求更复杂一点,比如我们不仅要统计全站的文章阅读总量,还想统计每篇文章各自的阅读量。
如果用第一种方法,我们得为每一篇文章创建一个键,article:read:1001(假设1001是文章ID),然后对这个键进行 INCR,这样虽然也可以,但是当文章数量巨大时,会产生非常多的键,管理起来可能不太方便。
这时候可以用 Redis 的哈希结构,我们可以这样做:
- 创建一个哈希键,
article:read:count。 - 每当有用户阅读了一篇文章(ID为1001)时,我们就执行命令:
HINCRBY article:read:count 1001 1。 - 这个命令的意思是,在
article:read:count这个哈希表里,给字段(field)名为 "1001" 的值增加 1。 - 如果要查询全站所有文章的总阅读量,我们可以先通过
HGETALL article:read:count获取所有文章ID和对应的阅读量,然后在代码里把这些阅读量加起来,不过要注意,如果文章非常多,这个HGETALL可能会比较慢,可以考虑用HSCAN命令分批遍历。 - 更常用的是查询单篇文章的阅读量,直接用
HGET article:read:count 1001,速度同样非常快。
这种方法的好处是能把相关联的计数数据组织在一起,结构更清晰,其原子性操作由 HINCRBY 命令保证,适用于分类计数场景。
第三种方法,适用于判断是否存在再计数的:使用集合(Set)或 HyperLogLog。
前面两种方法虽然快,但有个前提:我们不计较统计的对象是不是重复的,比如文章阅读量,通常同一个人重复阅读是算作多次的,但如果我们的统计需求是 “去重” 的,比如统计一篇文的独立访客数(UV),即同一个用户一天内访问多次只算一次,这时候就要换方法了。
最直接的想法是使用集合,每个用户有一个唯一标识(比如用户ID或设备ID)。
- 我们可以为每篇文章创建一个集合键,
article:uv:1001。 - 当用户访问时,我们执行
SADD article:uv:1001 user_id命令,这个命令的作用是,如果这个 user_id 不在集合中,就把它加进去;如果已经在里面了,就什么都不做(实现了去重)。 - 统计总数时,使用
SCARD article:uv:1001命令,它能立刻返回集合中的元素个数,也就是去重后的独立访客数。
这个方法非常准确,但缺点是比较耗内存,如果一篇文章有百万级的 UV,那么这个集合就会存储百万个 user_id,占用的空间会很大。
为了解决内存消耗的问题,Redis 提供了一个叫做 HyperLogLog 的数据结构,它用来做去重计数是神器。
- 它的用法和集合类似:
PFADD article:uv:1001 user_id用于添加元素,PFCOUNT article:uv:1001用于获取去重后的估算值。 - 为什么是“估算值”?因为 HyperLogLog 的优点是在数据量极大的情况下,只需要占用非常小的固定内存(约12KB),就能计算出非常接近真实值的去重数量,误差率大概在 0.81% 左右。
- 对于像全网UV、大型活动参与人数这种数据量极大、可以接受微小误差的统计场景,HyperLogLog 是完美选择,根据 Redis 文档,HyperLogLog 的核心优势就在于其惊人的空间效率。
用 Redis 快速搞定总数统计,其实就是根据不同的业务场景,选择最合适的“计数器”:
- 要简单粗暴的总数,允许重复计数:用
INCR命令,又快又准。 - 要分门别类地计数:用哈希(Hash)结构的
HINCRBY命令。 - 要精确的去重计数,且数据量不大:用集合(Set)的
SADD和SCARD命令。 - 要海量数据的去重计数,能接受微小误差:用 HyperLogLog 的
PFADD和PFCOUNT命令,省内存是它的绝活。
核心就是利用 Redis 内存操作的速度和它提供的原子性计数命令,把耗时的实时计算转变为高效的键值查询,从而轻松应对高并发、大数据量的统计需求。

本文由寇乐童于2025-12-31发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/71893.html
