慢性症Redis模糊查询之苦(redis模糊查询很慢)
慢性症:Redis模糊查询之苦
Redis 是一款常用的键值存储系统,也常被用作数据库、缓存、消息队列等。其中模糊查询是一项常用的功能,但诸如 `LIKE` 这样的模糊查询并不是 Redis 的本职工作,这就导致了 Redis 在模糊查询上的一些局限性。在实际使用中,我们可能会遇到 Redis 模糊查询性能差、慢、缺乏灵活度等一些问题。
一、纯 Redis 模糊查询
1.1 Redis `KEYS` 命令
我们都知道 Redis 有一个 `KEYS` 命令可以用来搜索以某个模式开头的键值。例如,如果有以下几个键:
foo:bar:baz
foo:qux:bazfoo:bar:buz
baz:qux:foo
我们使用 `KEYS foo:*` 查询,便可以找到所有以 `foo:` 开头的键:
foo:bar:baz
foo:qux:bazfoo:bar:buz
但是,`KEYS` 命令是阻塞性的,执行时会阻塞其他 Redis 客户端的操作,如果我们的 Redis 中有大量的键值对,则慢查询就变得非常明显。
1.2 Redis 数据结构的查询能力
除了 `KEYS` 命令外,Redis 中的 Sorted Set 以及 Set 集合等数据类型也可以实现模糊查询。例如,如果有一个 Sorted Set `myset`,存储了以下数据:
ZADD myset 1 foo
ZADD myset 2 barZADD myset 3 baz
ZADD myset 4 quxZADD myset 5 buz
我们可以使用 `ZRANGEBYLEX myset [f [o` 查询以 f 开头的值:
> ZRANGEBYLEX myset [f [o
1) "foo"2) "qux"
但是,这里也有一些限制。这些数据结构的查询方式都是有限制的,不如 SQL 中的模糊查询丰富灵活;这些查询都是基于字符串的匹配,不支持模式匹配,无法匹配多个字段。
二、Redis 与 Lua 脚本的模糊查询
为了解决模糊查询的问题,我们可以将查找逻辑写入到 Lua 脚本中,通过 EVAL 命令执行,这样可以减轻 Redis 在查询过程中的压力。下面我们来看一个例子:
-- 脚本名称:scan_keys.lua
local cursor = 0local pattern = ARGV[1]
local result = {}
repeat local keys = redis.call('SCAN', cursor, 'MATCH', pattern)
cursor = tonumber(keys[1]) local data = keys[2]
for _, key in iprs(data) do table.insert(result, key)
end
until cursor == 0
return result
这个脚本使用 Redis 的 `SCAN` 命令进行模糊查询,每次查询 10000 个键值,直到全部查询完毕为止。我们可以这样调用该脚本:
EVAL sha1('scan_keys.lua') 0 'foo:*'
其中,`0` 表示不使用 key,`foo:*` 表示查询以 `foo:` 开头的键值。
这种方式比纯 Redis 查询效率要高,但仍然存在一些问题。Lua 脚本可能比原汁原味的 Redis 命令慢;Lua 脚本过长可能会导致客户端和服务器之间的通讯带宽被耗尽;该脚本仍然需要扫描整个 Redis 数据库,对于大型数据集,仍会产生较大的负担。
三、Redis 与 Redisearch 的模糊查询
对于企业级别的 Redis 查询,Redisearch 是一个不错的建议。Redisearch 是一个基于 Redis 的全文搜索引擎,支持模糊查询、原子全文搜索、高亮以及排名等功能。其中,针对模糊查询,Redisearch 提供了以下功能:
FT.SEARCH
FT.SUGGGET [FUZZY [MAX RESULTS ] [PREFIX]]
其中,`FT.SEARCH` 支持基于某个查询的全文搜索,支持模糊查询、原子全文搜索以及排名等功能;`FT.SUGGGET` 则支持自动完成,支持模糊匹配和前缀匹配。
例如,我们使用以下命令创建一个索引:
FT.CREATE myindex ON NOFIELDS PREFIX 1 "foo:" SCHEMA name TEXT
然后,我们可以使用以下命令进行模糊查询:
FT.SEARCH myindex foo* LIMIT 0 100
其中,`foo*` 表示以 `foo` 开头的字符串,`LIMIT 0 100` 表示查询结果从 0 开始,返回 100 个结果。
Redisearch 的优点在于模糊查询效率高、精度高,支持前缀匹配、模糊匹配等灵活查询方式。但是缺点是需要预先创建索引,在数据集变化后需要及时维护索引,否则可能会导致查询失败。
总体而言,Redis 模糊查询在性能和灵活度上都有不足之处,我们需要根据实际情况选择适合的查询方式。了解以上几种方法,我们可以在实际使用中根据实际需要和数据集大小选择最适合自己的查询方式。