Cassandra - 二级索引和查询性能

Cassandra - secondary index and query performance

我的 table 架构是:
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 的最佳模式。

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

其次,如果您只想不必为每个请求包含 'acceptation' 字段,您有两种可能性:

1 - 您可以使用 'acceptation' 作为聚类列:

PRIMARY KEY ((userId), accepted, ts_accepted)

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

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

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

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

2 - 创建两个单独的 tables

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

所以在你的情况下,你会为​​第一个 table 和第一个和第二个请求保留你的第一个模式,

并且您将使用相同的数据创建另一个 table,但架构略有不同,如果 'accepted' 不需要成为主键的一部分(如您为你的第二个模式做了),或者像这样的主键:

PRIMARY KEY ((userId), accepted, ts_accepted)

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

编辑:

您还在主键中使用了时间戳。请注意,如果您可以让同一用户在此 table 中创建两行,则可能会出现问题。因为时间戳不保证唯一性:如果两行在同一毫秒内创建会怎样?

您可能应该使用 TimeUUID。这种在 Cassandra 中非常常用的类型通过组合时间戳和 UUID 来保证唯一性。

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