这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战
起因
昨天在群里看到了一道面试题,题目是:
1 | vbnet复制代码假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的 |
看群里的小伙伴们各抒己见,最后总结起来有如下三个命令:
- keys:用于查找所有符合给定模式
pattern
的key
- smembers:返回集合
key
中的所有成员 - scan:增量迭代当前数据库中的所有数据库键
其中,keys
和smembers
命令都是返回所有成员,时间复杂度为O(n)O(n)O(n)。scan
虽然时间复杂度也是O(n)O(n)O(n),但是它采用的是增量的方式,数据量较大的场景下,不会像前两者一样一直阻塞着线程。
上面都是通过网上搜索来的答案,具体是不是这样我也不确定。于是我跑去github
上面下了redis
的源码,看看源码里面是怎么样的。
源码
在源码文件中有一个命令表,位于redis\src\server.c
文件中,在这里我们可以快速的找到各个命令对应的函数入口。
命令的入口找到了,我们就可以分别跳转过去看它的对应实现了。
keys
在keys
命令函数中可以看到它是遍历了整个键空间字典,将与给定的pattern
匹配的添加到返回列表中。
1 | c复制代码void keysCommand(client *c) { |
smembers
smembers
命令这边调用的是sinterGenericCommand
函数,搜索范围传递的是0
,表示全局搜索。
1 | C复制代码/* SINTER key [key ...] */ |
scan
由于scanGenericCommand
代码太长来这里就不全贴出来,小伙伴们感兴趣的话可以下载源码搜索一下。
该函数的大概实现逻辑应该是先解析附带的参数,得到需要返回的数据长度以及游标值,再迭代集合获取所需数据。
具体的入口函数为disScan
。
1 | c复制代码/* The SCAN command completely relies on scanGenericCommand. */ |
最后
由于我是Java出身,对于c/c++的语法不熟悉,备注都是阅读源码后结合注释进行理解的,如果文中有备注错误的地方,希望大佬们可以帮忙指点一下!
本文转载自: 掘金