redis 命令 exists vs get

本贴最后更新于 862 天前,其中的信息可能已经时移世改

功能对比

exists

参数格式:

EXISTS key [key ...]

用于判断某个键是否存在

get

参数格式:

GET key

用于获取键对应的值。

由上可知,相同的场景只有判断键是否存在。

性能对比

使用下面命令向 Redis 里面注入大量数据:

public class FillData { private static final Jedis jedis = new Jedis("127.0.0.1", 6379); private static void fillData(long min, long max, SetParams params) { for (long i = min; i < max; i++) { jedis.set("key_0000000" + i, "value_0000000" + i, params); if (i % 1000 == 0) { System.out.println("count=" + i); } } } public static void main(String[] args) { SetParams params = new SetParams(); FillData.fillData(0, 5000000, params); params.ex(50000L); FillData.fillData(50000000, 55000000, params); } }

使用下面代码对比相应时间:

public class ExistsVSGet { private static final Jedis jedis = new Jedis("127.0.0.1", 6379); private static void exists() { long begin = System.nanoTime(); jedis.exists("key_aaaaaaa"); long end = System.nanoTime(); System.out.println("exists cost=" + (end - begin)/1000); } private static void get() { long begin = System.nanoTime(); jedis.exists("key_aaaaaaa"); long end = System.nanoTime(); System.out.println("get cost=" + (end - begin)/1000); } private static void test() { for (int i=1; i< 10; i++) { jedis.get("0000000" + i); } } public static void main(String[] args) { ExistsVSGet.test(); ExistsVSGet.get(); ExistsVSGet.exists(); } }

执行结果如下:

get cost=476 exists cost=279

由此可见,get 性能要比 exists 差。

源码分析

get 命令核心查找 key 代码

robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply) { robj *o = lookupKeyRead(c->db, key); if (!o) addReply(c,reply); return o; }

其中 lookupKeyRead 的实现:

robj *lookupKeyRead(redisDb *db, robj *key) { return lookupKeyReadWithFlags(db,key,LOOKUP_NONE); }

exists 命令核心实现:

void existsCommand(client *c) { long long count = 0; int j; for (j = 1; j < c->argc; j++) { if (lookupKeyReadWithFlags(c->db,c->argv[j],LOOKUP_NOTOUCH)) count++; } addReplyLongLong(c,count); }

exists 和 get 命令都调用了 lookupKeyReadWithFlags,我们看下这个函数的实现:

robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) { robj *val; if (expireIfNeeded(db,key) == 1) { if (server.masterhost == NULL) goto keymiss; if (server.current_client && server.current_client != server.master && server.current_client->cmd && server.current_client->cmd->flags & CMD_READONLY) { goto keymiss; } } val = lookupKey(db,key,flags); if (val == NULL) goto keymiss; server.stat_keyspace_hits++; return val; keymiss: if (!(flags & LOOKUP_NONOTIFY)) { server.stat_keyspace_misses++; notifyKeyspaceEvent(NOTIFY_KEY_MISS, "keymiss", key, db->id); } return NULL; }

可见都是先判断了确认了是否过期(过期 key 单独保存在另一个 dict 里面),再没有过期的情况下查找了 db 库,总体查找时间是一致的。

但是,我们可以发现,get 命令返回了键对应的值,exists 返回了个数,一般键对应的值较大,传输时间较长。所以相对较慢。

结论

在判断 key 是否存在的场景下:

  • exists 速度更快,可以忽略类型。
  • get 只适用于 string 类型,当值越大时,速度越慢。
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖
  • Jedis
    7 引用 • 11 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
zeekling
应无所住,而生其心。 --《金刚经》 吾生也有涯,而知也无涯。 --《庄子》 香港