聚集列排序与二级索引的 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 中使用索引总是好的。
我的模式是:
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 中使用索引总是好的。