当前位置:首页 > 问答 > 正文

Redis能不能条件查询?其实你可能没发现它隐藏的那些惊喜功能

很多人第一次接触Redis,都觉得它就是个简单的键值对存储,像个高级的HashMap,你给它一个key,它立刻还你一个value,速度飞快,但好像干不了复杂的事,比如像SQL数据库那样的条件查询(WHERE age > 18 AND name = ‘张三’),如果你也这么想,那Redis可要喊冤了,它确实不像关系型数据库那样天生自带完整的查询语言,但它有一系列巧妙的“工具”,组合起来能让你用另一种思路实现非常强大甚至更高效的条件查询,今天我们就来挖一挖Redis这些隐藏的惊喜功能。

核心思路:空间换时间,预先组织数据

要理解Redis的查询逻辑,首先要忘掉“现场计算”的模式,关系型数据库是你把数据丢进去,它现场根据你的条件去扫描、计算,而Redis的思路是,你得在写入数据的时候,就多花一点功夫,把数据按照未来可能查询的方式“预先整理”好,这叫“空间换时间”,虽然多占了一点内存,但查询时速度快得惊人,因为几乎不需要计算。

利用各种数据结构,建立“索引”

这才是Redis的精髓所在,它支持的String(字符串)、List(列表)、Set(集合)、Sorted Set(有序集合)、Hash(哈希)这些数据结构,就是你构建索引的积木。

Redis能不能条件查询?其实你可能没发现它隐藏的那些惊喜功能

  • 等值查询(WHERE name = ‘张三’): 你可以用Set(集合),你要查询所有男性用户,那么在创建一个用户Hash记录的同时,你可以往一个叫 user:gender:male 的Set里,添加这个用户的ID,这样,当你需要所有男性用户时,直接 SMEMBERS user:gender:male,瞬间就能拿到所有ID,然后再用这些ID去获取完整的用户信息,这就像为“性别”字段建了一个索引。
  • 范围查询(WHERE age > 18): 这是Sorted Set(有序集合) 的天下,有序集合每个成员都有一个分数(score),你可以把用户的年龄作为分数,用户ID作为成员存进去,一个叫 user:age 的有序集合,要查年龄大于18岁的用户?一条命令 ZRANGEBYSCORE user:age 18 +inf 就搞定了,返回的就是所有符合条件的用户ID,同样,查询分数排名前10的用户,用 ZREVRANGE user:age 0 9 也能轻松实现。
  • 多条件组合查询(WHERE gender = ‘male’ AND age > 18): 这需要一点技巧,用到Set的交叉并集操作,你先从 user:gender:male 这个Set里拿到所有男性用户的ID集合A,再从 user:age 这个Sorted Set里通过 ZRANGEBYSCORE 拿到年龄大于18的用户ID集合B(注意,这里可能需要一些客户端处理,或者用Lua脚本保证原子性),对集合A和B取交集 SINTER user:gender:male temp:age_above_18,结果就是同时满足两个条件的用户ID,虽然比单条件多了一步,但速度依然非常快。

不是查询,但让查询更强大的功能

有些Redis功能本身不是查询,但能极大地增强你处理查询结果的能力。

  • Lua脚本: 上面提到的多条件查询,如果步骤复杂,网络来回传输数据效率低,Redis支持Lua脚本,你可以把复杂的查询逻辑写成一个脚本,一次性发送到Redis服务器执行,服务器会原子性地完成所有操作(比如先计算、再取交集、最后返回结果),不仅效率高,还避免了并发问题,这相当于你在Redis内部写了一个自定义的查询函数。
  • RedisSearch模块(官方强力推荐): 如果说上面的方法是“手动挡”,那RedisSearch就是“自动挡”甚至是“智能驾驶”,它是一个官方支持的模块,为Redis提供了完整的全文搜索和二级索引功能,你可以像用搜索引擎一样,进行复杂的文本搜索、模糊匹配、数值过滤、地理空间查询等,直接查询“标题包含‘Redis’且发布时间在最近一周、点赞数超过100的文章”,这已经完全超越了传统键值对的能力,是Redis在查询方面最大的惊喜,但需要注意,这需要你额外加载该模块。

总结一下

Redis能不能条件查询?其实你可能没发现它隐藏的那些惊喜功能

回到最初的问题:Redis能不能条件查询?答案是:能,而且很强大,但方式不同。

你不能指望像用MySQL那样写一句SQL了事,你需要转变思维,把Redis看作一个数据结构和功能的工具箱,在设计数据模型时,就要有预见性,思考未来会如何查询,并利用合适的数据结构(Set, Sorted Set)提前构建好“索引”,对于简单的等值、范围查询,原生数据结构就能高效解决;对于复杂的多条件组合或全文搜索,借助Lua脚本或RedisSearch模块,Redis同样能交出令人惊艳的答卷。

下次当你觉得Redis功能单一时,不妨想想它这些隐藏的惊喜,它不是在模仿SQL,而是在用自己独特的“Redis Way”解决同样的问题,并且在性能上往往能带来意想不到的优势。

(注:本文核心思路和示例参考了Redis官方文档中关于数据结构的介绍以及《Redis实战》等经典书籍中提出的设计模式,同时结合了RedisSearch模块的官方说明。)