Cassandra - 二级索引和查询性能

时间:2015-08-16 16:26:07

标签: sql cassandra query-performance database nosql

我的表格架构是: 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专家......请建议我实现这一目标的最佳方案.A或B.

1 个答案:

答案 0 :(得分:1)

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

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

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

PRIMARY KEY ((userId), accepted, ts_accepted)

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

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

您将更有效地获得相同的结果。

但是这种方法存在问题,它会创建更大的分区,这对于良好的性能来说并不是最好的。

2 - 创建两个单独的表

这种方法对于卡桑德拉精神来说更为充足。使用Cassandra,如果可以提高请求的效率,则复制数据并不罕见。

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

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

PRIMARY KEY ((userId), accepted, ts_accepted)

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

编辑:

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

您应该使用TimeUUID。这种在Cassandra中非常常用的类型通过组合Timestamp和UUID来保证单一性。

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