【问题标题】:Cassandra - alternate way for clustering key with ORDER BY and UPDATECassandra - 使用 ORDER BY 和 UPDATE 集群键的替代方法
【发布时间】:2015-11-17 07:00:17
【问题描述】:

我的架构是:

CREATE TABLE friends (
     userId timeuuid,
     friendId timeuuid,
     status varchar, 
     ts timeuuid,   
     PRIMARY KEY (userId,friendId)
);

CREATE TABLE friends_by_status (
    userId timeuuid,
    friendId timeuuid,
    status varchar, 
    ts timeuuid,   
    PRIMARY KEY ((userId,status), ts)
)with clustering order by (ts desc);

在这里,每当提出好友请求时,我都会在两个表中插入记录。 当我想检查用户的一对一状态时,我会使用这个查询:

SELECT status FROM friends WHERE userId=xxx AND friendId=xxx;

当我需要查询所有处于待处理状态的记录时,我会使用:

SELECT * FROM friends_by_status WHERE userId=xxx AND status='pending';

但是,当状态发生变化时,我可以更新 'friends' 表中的 'status' 和 'ts',但不能更新 'friends_by_status' 表都是 PRIMARY KEY 的一部分。

您可以看到,即使我对其进行非规范化,我肯定需要更新 'friends_by_status' 表中的 'status' 和 'ts' 以保持一致性。

我可以保持一致性的唯一方法是删除记录并再次插入。
但在 cassandra 模型中也不建议频繁删除。 As said in Cassaandra Spottify summit.

我发现这是 Cassandra 的最大限制。

有没有其他方法可以解决这个问题。

感谢任何解决方案。

【问题讨论】:

    标签: cassandra cassandra-2.0 clustered-index nosql


    【解决方案1】:

    我不知道您需要多长时间部署它,但在 Cassandra 3.0 中,您可以使用物化视图来处理它。您的朋友表将是基表,friends_by_status 将是基表的视图。当您更改基表时,Cassandra 会注意更新视图。

    例如:

    CREATE TABLE friends ( userid int, friendid int, status varchar, ts timeuuid, PRIMARY KEY (userId,friendId) );
    CREATE MATERIALIZED VIEW friends_by_status AS
        SELECT userId from friends WHERE userID IS NOT NULL AND friendId IS NOT NULL AND status IS NOT NULL AND ts IS NOT NULL
        PRIMARY KEY ((userId,status), friendID);
    
    INSERT INTO friends (userid, friendid, status, ts) VALUES (1, 500, 'pending', now());
    INSERT INTO friends (userid, friendid, status, ts) VALUES (1, 501, 'accepted', now());
    INSERT INTO friends (userid, friendid, status, ts) VALUES (1, 502, 'pending', now());
    SELECT * FROM friends;                
    
     userid | friendid | status   | ts
    --------+----------+----------+--------------------------------------
          1 |      500 |  pending | a02f7fe0-49f9-11e5-9e3c-ab179e6a6326
          1 |      501 | accepted | a6c80980-49f9-11e5-9e3c-ab179e6a6326
          1 |      502 |  pending | add10830-49f9-11e5-9e3c-ab179e6a6326
    

    所以现在在视图中您可以按状态选择行:

    SELECT * FROM friends_by_status WHERE userid=1 AND status='pending';
    
     userid | status  | friendid
    --------+---------+----------
          1 | pending |      500
          1 | pending |      502
    
    (2 rows)
    

    然后当你更新基表中的状态时,它会在视图中自动更新:

    UPDATE friends SET status='pending' WHERE userid=1 AND friendid=501;
    SELECT * FROM friends_by_status WHERE userid=1 AND status='pending';
    
     userid | status  | friendid
    --------+---------+----------
          1 | pending |      500
          1 | pending |      501
          1 | pending |      502
    
    (3 rows)
    

    但请注意,在视图中您不能将 ts 作为键的一部分,因为您只能从基表中添加一个非键字段作为视图中键的一部分,在您的情况下是将“状态”添加到键中。

    如果您想尝试一下,我认为 3.0 的第一个 beta 版本将于明天发布。

    【讨论】:

    • 感谢您提到 3.0....它真的很棒。但不确定何时发布稳定版本。无论如何,在每个用户上都有收集列是否是个好主意,例如“pending_requests”、“accepted_requests”、“rejected_requests”。它会提供良好的性能,因为每列可能有很多值。例如:pending_request 集合中可能有 200-1000 个项目。这是一个好习惯吗?
    • 到目前为止 3.0 对我来说已经相当稳定了。开发人员为此付出了很多努力。我实际上打算为您的用例向您推荐集合。我相信集合是作为一个数据块读取的,所以如果您经常读取大型集合,那么这可能会影响性能,但最好是尝试一下。
    • @JimMeyer 当我们有多个非密钥时有解决方案吗?
    【解决方案2】:

    为什么您需要将状态作为第二个表的主键?如果这是您的架构:

    CREATE TABLE friends_by_status (
    userId timeuuid,
    friendId timeuuid,
    status varchar, 
    ts timeuuid,   
    PRIMARY KEY ((userId), status, ts) 
    with clustering order by (ts desc));
    

    您可以根据需要更新状态并仍按其过滤。您将在一个分区下存储更多数据,但您似乎为用户拥有的每个朋友存储一行。这将与第一个表中的相同,因此我认为分区大小不是问题。

    【讨论】:

    • 更新friends_by_status set status='accepted' where userId=now();此查询不起作用,因为状态是主键的一部分。
    • 刚刚重新考虑了您要做什么。在您当前的模型中,您将如何指定要更新的个人友谊关系?执行 update friends_by_status set status='accepted' where userId=now() 将更新该用户的所有行,即使您被允许这样做。您可能可以查看的一个选项是使用集合(集合或列表)来处理您可以动态更改的“待处理的朋友请求”。
    • 我确实考虑过收藏。在每个用户上都有列是否是个好主意,例如“pending_requests”、“accepted_requests”、“rejected_requests”。?它是否会提供良好的性能,因为每列可能具有丰富的值。例如:pending_request 集合中可能有 200-1000 个项目。这是一个好习惯吗?
    猜你喜欢
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 2017-09-25
    • 2014-09-10
    • 2019-09-07
    • 2016-06-14
    相关资源
    最近更新 更多