【问题标题】:Cassandra - secondary index and query performanceCassandra - 二级索引和查询性能
【发布时间】:2015-11-09 07:45:12
【问题描述】:

我的表格架构是:
A)

CREATE TABLE friend_list (
    userId uuid,
    friendId uuid,
    accepted boolean, 
    ts_accepted timestamp,
    PRIMARY KEY ((userId ,accepted), ts_accepted)
   ) with clustering order by (ts_accepted desc);

在这里我可以执行如下查询:

1.  SELECT * FROM friend_list WHERE userId="---" AND accepted=true;
2.  SELECT * FROM friend_list WHERE userId="---" AND accepted=false;
3.  SELECT * FROM friend_list WHERE userId="---" AND accepted IN (true,false);

但第三个查询涉及更多读取,所以我尝试像这样更改架构:

B)

 CREATE TABLE friend_list (
        userId uuid,
        friendId uuid,
        accepted boolean, 
        ts_accepted timestamp,
        PRIMARY KEY (userId , ts_accepted)
       ) with clustering order by (ts_accepted desc);
CREATE INDEX ON friend_list (accepted);

使用这种 B 型模式,第一个和第二个查询可以工作,但我可以将第三个查询简化为:

3. SELECT * FROM friend_list WHERE userId="---";

我相信第二个模式为第三个查询提供了更好的性能,因为它不会对每一行进行条件检查。

Cassandra 专家...请建议我实现 this.A 或 B 的最佳架构。

【问题讨论】:

    标签: sql cassandra query-performance database nosql


    【解决方案1】:

    首先,您是否知道您的第二个架构与第一个架构完全不同?在第一个中,“接受”字段是键的一部分,但在第二个中根本不是!您没有相同的唯一约束,您应该检查它是否对您的模型有问题。

    其次,如果您不想为每个请求都包含“接受”字段,那么您有两种可能性:

    1 - 您可以使用“接受”作为聚类列:

    PRIMARY KEY ((userId), accepted, ts_accepted)
    

    这样你的第三个请求可以是:

    SELECT * FROM friend_list WHERE userId="---";
    

    你会更有效地得到同样的结果。

    但是这种方法有一个问题,它会创建更大的分区,这不是最好的性能。

    2 - 创建两个单独的表

    这种方法更适合 Cassandra 精神。使用 Cassandra,如果可以提高请求的效率,复制数据并不少见。

    因此,在您的情况下,您将为第一个表以及第一个和第二个请求保留第一个模式,

    并且您将创建另一个具有相同数据但架构略有不同的表,如果“接受”不需要成为主键的一部分(就像您对第二个架构所做的那样),则使用二级索引,或者像这样的主键:

    PRIMARY KEY ((userId), accepted, ts_accepted)
    

    如果可能的话,我肯定会更喜欢第二个表的二级索引,因为接受的列的基数较低 (2),因此非常适合二级索引。

    编辑:

    您还在主键中使用了时间戳。请注意,如果您可以让同一用户在此表中创建两行,则可能会出现问题。因为时间戳不能保证唯一性:如果两行的创建时间相同,会发生什么情况?

    您可能应该使用 TimeUUID。这种类型在 Cassandra 中非常常用,通过结合 Timestamp 和 UUID 来保证唯一性。

    此外,主键中的时间戳可以在 Cassandra 节点中创建临时热点,绝对最好避免。

    【讨论】:

    • 所以你建议有两个表,首先是我的模式 A 用于查询 1 和 2,第二个表是我的模式 B 用于查询 3。但是为什么我不能只使用模式 B不需要所有 3 个查询作为接受的主键。
    • 另外,如果我使用 PRIMARY KEY ((userId), accepted, ts_accepted),我无法单独对 ts_accepted 聚类列进行排序,因为我必须同时对“接受”和“进行排序” ts_接受'。每次都按“接受”排序会带来性能问题。
    • 您的第一个模式似乎表明您需要主键中的“已接受”字段。如果您不这样做,那么对于您的特定用例,我认为是的,索引列很好(基数低,变化很少),但它仍然比将“接受”作为集群列慢。尽管对于您的情况,差异应该很小。
    猜你喜欢
    • 2014-03-05
    • 1970-01-01
    • 2016-11-28
    • 2016-06-13
    • 2023-04-08
    • 2018-07-21
    • 2021-11-21
    • 2013-12-04
    • 1970-01-01
    相关资源
    最近更新 更多