【问题标题】:Data modelling for consistent secondary keys with Cassandra使用 Cassandra 对一致的辅助键进行数据建模
【发布时间】:2015-01-26 22:06:39
【问题描述】:

与卡桑德拉,

我想用唯一的uuid 表示所有用户对象,但还包含一组零个或多个辅助用户键以映射到用户。每个辅助键应映射到一个且只有一个用户(id)。因为我需要能够快速查找辅助键来查找用户,所以我维护了一个单独的查找表,而不是辅助INDEX

我已经对数据进行了这样的建模,但我对替代方案持开放态度:

CREATE TABLE users (
    userid uuid PRIMARY KEY,
    name text,
    secondarykeys set<text>
);
CREATE TABLE user_secondarykeys (
    secondarykey text,
    userid uuid,
    PRIMARY KEY(secondarykey)
);

一个典型的用例是这样的:

我得到了这个用户的辅助键mail:andreas@example.org,我想看看是否存在任何具有该辅助键的用户,如果不存在,我想创建一个新的用户对象。

我可以查找辅助键:

SELECT * FROM "user_secondarykeys" WHERE secondarykey = "mail:andreas@example.org";

如果我没有找到任何匹配项,我可以插入一个新用户:

BEGIN BATCH
    INSERT INTO users (userid, name, secondarykeys) VALUES (77059e45-5fac-460b-9c4f-47528c292be0, "Andreas", {'mail:andreas@example.org'});
    INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas@example.org', 77059e45-5fac-460b-9c4f-47528c292be0);
APPLY BATCH;

我的问题是这会导致数据不一致,因为在我的选择和插入之间,用户可以使用该辅助键插入。

我在想,如果在 user_secondarykeys 中已经存在辅助键的情况下,我可以使我的 INSERT 事务失败,那将起作用,因为它还应该将插入恢复到用户表中,因为事务的原子属性.但是,如果存在辅助键,我不知道有什么方法可以使 INSERT 失败。如果我将IF NOT EXISTS 添加到第二个插入中,它不会恢复事务,它只会避免插入user_secondarykeys,但它仍会插入users

感谢任何有关如何以可靠方式实现此用例的建议。谢谢。

【问题讨论】:

    标签: cassandra data-modeling cql cassandra-2.0


    【解决方案1】:

    起初,我认为您的模型非常复杂,我不确定我是否正确理解了您的所有要求。

    因此,如果您首先获得此辅助密钥,然后您必须决定要做什么 - 添加或不添加用户 - 那么以下内容将为您工作:

    不要使用 SELECT 语句检查 user_secondarykeys 表中是否出现特定的辅助键,而是使用以下命令:

    INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas@example.org', 77059e45-5fac-460b-9c4f-47528c292be0) IF NOT EXISTS;
    

    因此,如果适用,则表示此辅助密钥未与任何用户连接-因此有两种情况:用户不存在或用户存在并且有人想为他添加新的辅助密钥。以下将在这两种情况下完成工作:

    INSERT INTO users(userid, name, secondarykeys) VALUES(77059e45-5fac-460b-9c4f-47528c292be0, 'Andreas', secondarykeys = secondarykeys + 'mail:andreas@example.org')
    

    因为 Cassandra 中的插入/更新是幂等的(计数器除外),即使用户表中已经存在具有该 id 的用户,这也将起作用 - 这应该只为他添加另一个辅助键。

    此解决方案的优点是您可以及时消除这种可能使您“前后不一”的差距。您可以保证没有人会插入具有相同辅助密钥的两个用户。您指定用户根本不能有辅助键 - 在这种情况下,您可以直接将他添加到用户表中。

    我在想,如果在 user_secondarykeys 中已经存在辅助键的情况下,我可以使我的 INSERT 事务失败,那将起作用,因为它还应该将插入恢复到 users 表中,因为事务的原子属性.但是,如果存在辅助键,我不知道有什么方法可以使 INSERT 失败。如果我将 IF NOT EXISTS 添加到第二个插入,它不会还原事务,它只会避免插入到 user_secondarykeys,但它仍会插入到用户中。

    从 Cassandra 2.0.6 开始,您可以在批处理中使用条件语句,如果不满足任何条件,则该批处理中的所有指令都不会触发。这听起来不错,但有一个限制 - 批处理中的所有语句都必须在单个相同的分区上运行。据此,不可能进行跨分区/表条件的插入/更新/删除。所以在你的情况下:

    BEGIN BATCH
        INSERT INTO users (userid, name, secondarykeys) VALUES (77059e45-5fac-460b-9c4f-47528c292be0, "Andreas", {'mail:andreas@example.org'});
        INSERT INTO user_secondarykeys (secondarykey, userid) VALUES ('mail:andreas@example.org', 77059e45-5fac-460b-9c4f-47528c292be0) IF NOT EXISTS;
    APPLY BATCH;
    

    甚至不会通过查询验证,因为您在这里尝试对两个不同的表进行操作。

    我不确定这是否适合您的其他要求,我需要有关您的查询和数据速度/数量的更多信息。当然还有其他方法可以对此进行建模。

    如果每个用户都必须至少有一个指定的辅助键(例如电子邮件将是您的用户表的一个很好的唯一键),这将大大简化问题,但这是您的要求,所以除非您无法更改他们没有讨论。

    希望这会对您有所帮助。 祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-23
      • 2011-04-27
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多