我的表格架构是: 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.
答案 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节点中创建临时热点,绝对可以避免。