聚集列排序与二级索引的 Cassandra 性能

Cassandra performance on clustered column sorting vs secondary index

我的模式是:

A)

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

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);

哪个将为查询提供最佳性能:

SELECT * FROM friend_list WHERE userId="---" AND accepted=true;

据我了解,Cassandra 会自动按 ASC 顺序对聚集列进行排序,如果我们需要更改默认排序顺序以进行高效查询,我们会指定 DESC。

在我的模式 A 中,我将 'accepted' 作为聚簇键,但我需要对其进行不必要的排序,因为我肯定必须将 'ts_accepted' 排序为 DESC。 'accepted' 这种不需要的排序会影响性能吗?

如果是这样,假设我正在将 'accepted' 作为架构 B 中的二级索引。我知道二级索引对于低基数值(布尔值)来说并不坏。但是查询仍然可能有一些性能问题。

请告诉我实现此查询的有效方法。

我会选择 A。

如果你能避免二级索引,那就避免它(例外:你知道这将是一个会从中受益的 spark 作业)。如果您仍然需要二级索引,请重新设计您的模型。如果你还需要它,内心感觉很糟糕,然后再考虑。

您担心的聚类顺序成本不合适。无论如何,Cassandra 都会存储已排序的聚类列...ASC 或 DESC 不会改变任何事情。您使用的 space 稍微多了一点,但对于您的查询,您想点击 "accepted",所以这是合理的。我猜 ts_accepted 是出于其他原因需要的吗?这里唯一的问题是,如果您在查询中需要或有权访问 ts_accepted,则需要提供一个可接受的相等性过滤器。性能方面,我没有发现问题。

至于 B,极低基数列(如 bools)上的索引很糟糕。考虑数据是如何存储的——对于每个节点,Cassandra 维护一个 table,其中键是值(真/假),值是该节点的所有数据的键与键匹配。这有可能成为一个非常广泛的专栏。如果您要为单独的 table 建模,您会这样做吗?不,你也不应该用索引来做。

我不知道其余的数据,但如果您希望获得已被接受的朋友,为什么还要使用布尔值呢?您可以使用 ts_accepted 列来推断布尔值。如果它们有值,就会被接受,对吗?

您应该注意的一件事是您不能更新属于 pk 的列。

最后,您正在为您的查询点击分区键 (UserId)。这对您的查询非常有用。这意味着它将恰好命中一个分区。根据您的用例(和条目的大小),加载整个分区并过滤客户端/应用程序端甚至可能是可行的。当然,这取决于预期的好友列表大小,以及数据大小与网络流量与您需要/愿意做的应用程序处理。例如,加载 100 个条目并过滤接受的应用程序端,以及通过过滤数据库端加载 50 个条目可能具有相似的性能数字。

Which will give the best performance for the query : SELECT * FROM friend_list WHERE userId="---" AND accepted=true;

架构 (A) 将为您提供更好的查询性能。

I need to sort it unnecessarily as I definitely have to sort 'ts_accepted' to DESC

如果首先按 "accepted" 排序的结果顺序不影响您的代码逻辑(记录顺序正确则无需创建索引)

Problem with Schema (B)

在已接受的基础上创建索引将创建一个隐藏的列族,其架构类似于

CREATE TABLE friend_list_accept_idx (
        accepted boolean,
        userId uuid, 
        ts_accepted timestamp,
        PRIMARY KEY (accepted),userId , ts_accepted)
       );

这对您来说是不必要的维护开销。避免在 cassandra 中使用索引总是好的。