【问题标题】:Can Redis handle this simple queryRedis 可以处理这个简单的查询吗
【发布时间】:2014-12-18 18:01:39
【问题描述】:

我一直在研究 Redis 与关系数据库相比的功能,但没有涉及响应时间、可扩展性等 NFR 问题,我知道 Redis 在这些方面表现出色。

例如,这是一个 list of use-cases,Redis 可以为 Web 应用程序处理。
话虽如此,Redis 的一个已知缺点是进行业务分析,但是与 MySQL 相比,为了使 Redis 的效率降低,分析应该有多复杂?

例如如果 MySQL 中有如下数据结构:
Table: User Columns: Id(PK), Name(VarChar), Age(Int) 表格: 消息 列: UserID(FK)、Content(VarChar)、Importance(Int)

在我的应用程序中,我想使用以下 2 个查询:

 1. SELECT Content FROM Message WHERE Importance > 2;
 2. SELECT Content FROM Message,Users WHERE  User.Id=Message.UserID and
    User.Age > 30;

我的问题:
我可以使用 Redis 来存储上面的 Datastructure 并以与 MySQL 相同(或更高)的效率进行查询吗?

【问题讨论】:

    标签: redis relational-database


    【解决方案1】:

    简短回答:是的。

    长答案:Redis 是一项了不起的技术,但它不是关系数据库。包括 Redis 在内的 NoSQL 是建立在数据需要根据使用的访问模式存储的前提下的。因此,要完成上述操作,您首先必须“正确”存储数据。

    要存储表的行,您似乎需要使用 Hash 数据结构。在 Redis 的术语中,以下是为 UserID 123 创建用户密钥的方法:

    HMSET user:123 id 123 name foo age 31
    

    注 1: 在构造密钥名称时使用冒号 (':') 只是一种约定。
    注 2: 而 ID 是已经是密钥名称的一部分,通常将其包含在 Hash 中的一个字段以便于访问。

    同样,以下是创建消息密钥(ID 为 987)的方法:

    HMSET message:987 id 987 userid 123 content bar importance 3
    

    现在有趣的部分来了 :) Redis 没有 FK 或索引,因此您必须维护数据结构,以帮助您根据需要获取数据。对于您的第一个查询,最好的选择是保留一个排序集,其中成员是消息 ID,分数是重要性。因此这样做:

    ZADD messages_by_importance 3 987
    

    获取重要性大于 2 的消息内容将通过以下伪 Python 代码所示的两个操作完成:

    messages = r.zrangebyscore('messages_by_importance', '(2', '+inf')
    for msg in messages:
        content = r.hget('message:' + msg, 'content')
        do_something(content)
    

    注 3: 这个 sn-p 非常幼稚,可以进行优化以获得更好的性能,但它应该为您提供基本的要点。

    对于第二个查询,您首先需要找到 30 岁以上的用户 - 再次,应该使用相同的排序集技巧:

    ZADD users_by_age 31 123
    ZRANGEBYSCORE users_by_age (30 +inf
    

    这将为您提供符合您条件的所有用户的列表,但您还需要跟踪(索引)每个用户的所有消息。为此,请使用 Set:

    SADD user:123:messages 987
    

    为了绑定所有内容,这里还有一个伪 sn-p:

    users = r.zrangebyscore('users_by_age', '(30', '+inf')
    for user in users:
        messages = r.smembers('user:' + user + ':messages')
        for msg in messages:
            content = r.hget('message:' + msg, 'content')
            do_something(content)
    

    这应该足以让您入门,但是一旦您牢牢掌握了基础知识,请考虑优化这些流程。根据您的需要,使用流水线、Lua 脚本和更智能的索引可以轻松获得收益......如果您需要任何进一步的帮助 - 只需询问:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多