为何不可使用Redis的KEYS命令

在Redis KEYS命令的文档中,有如下一句话:

consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases.

简而言之,KEYS命令性能很差,尽量不要在生产环境中使用。

不过官方文档也提到了,可以使用SCAN命令

那么,KEYS命令为什么性能差呢?

server.c中可以看到,KEYS命令被keysCommand函数处理

void keysCommand(client *c) {
    dictIterator *di;
    dictEntry *de;
    sds pattern = c->argv[1]->ptr;
    int plen = sdslen(pattern), allkeys;
    unsigned long numkeys = 0;
    void *replylen = addDeferredMultiBulkLength(c);

    di = dictGetSafeIterator(c->db->dict);
    allkeys = (pattern[0] == '*' && pattern[1] == '\0');
    while((de = dictNext(di)) != NULL) {
        sds key = dictGetKey(de);
        robj *keyobj;

        if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
            keyobj = createStringObject(key,sdslen(key));
            if (expireIfNeeded(c->db,keyobj) == 0) {
                addReplyBulk(c,keyobj);
                numkeys++;
            }
            decrRefCount(keyobj);
        }
    }
    dictReleaseIterator(di);
    setDeferredMultiBulkLength(c,replylen,numkeys);
}

db本来就是一个dict,所以直接拿到一个dictIterator di,然后依次遍历,整个KEYS操作的复杂度是O(n),n为redis中key的数量。

这个操作,会阻塞到redis进程的。

可以看到,redis对于KEYS *这种情况做了优化。

Leave a Reply

Your email address will not be published. Required fields are marked *