我们有一些由生成的UUID唯一标识的实体。我们需要支持按名称查询查找。我们还需要支持按名称排序。
我们知道不会有超过1000个这种类型的实体完全适合一行。硬编码主键是否可行,使用name作为聚类键,id作为聚类键以满足唯一性。让我们说我们需要学校实体。这是一个例子:
CREATE TABLE school (
constant text,
name text,
id uuid,
description text,
location text,
PRIMARY KEY ((constant), name, id)
);
初始状态会给我所有的学校,然后按照确切名称进行过滤。我们的理由是将所有学校放在单行中以便快速访问,将名称作为聚类列进行过滤,并将id作为聚类列以保证唯一性。我们可以使用constant = school
作为已知的硬编码值来访问此行。
我喜欢这个解决方案的是所有值都在一行中,我们得到快速读取。我们也可以通过聚类列轻松解决排序问题。我不喜欢的是constant
接近奇数的硬编码值。我们可以使用name
作为PK,但是我们将有1000条记录分布在几个分区中,可能发现没有名称的所有记录都会更慢并且不会被排序。
问题1
这是一个可行的解决方案吗?我们看不到有任何问题吗?我没有看到任何关于使用硬编码主键的Cassandra数据建模的例子可能是因为我们怀疑这个解决方案。
问题2
名称是可编辑的字段,很可能很少更改(有人可以输错字或学校可以更改名称),但它可以更改。实现这一目标的最佳方法是什么?删除批量内插入(LTE可以应用于带条件子句的同一行)?
答案 0 :(得分:2)
是的,对于这么小的数据集来说,这是一个很好的方法。仅仅因为Cassandra可以跨多个节点划分大型数据集并不意味着您需要为每个表使用该功能。通过对分区键使用常量,您告诉Cassandra您希望将数据存储在一个节点上,您可以按顺序快速访问它。关系数据库一直对单个节点中的数据起作用,所以这真的不是一件不寻常的事情。
为了安全起见,您可能希望使用高于1的复制因子,以便至少有两个单个分区的副本。这样,如果存储数据的一个节点出现故障,您就不会失去对数据的访问权。
如果您希望有很多客户(即数千个客户端)经常读写此表,这种方法可能会导致问题,因为它可能成为热点。只有1000条记录,您可以通过将表设置为缓存所有键和行来保留缓存在内存中的所有行。
你可能找不到很多这样做的例子,因为人们转向Cassandra以支持大数据集,他们希望使用多个分区来实现可扩展性。所以这些例子都是针对那个。
答案 1 :(得分:1)
这是一个可行的解决方案吗?我们看不到有任何问题吗?我没有看到任何关于使用硬编码主键的Cassandra数据建模的例子可能是因为我们怀疑这个解决方案。
我在今年早些时候的文章中简要介绍了这种类型的建模解决方案:We Shall Have Order!这就是所谓的"虚拟键,"其中每行具有相同的分区键。这是一种快捷方式,允许您通过群集列轻松地对所有行(在未绑定的SELECT *
上)进行排序。
此解决方案存在问题:
Cassandra允许每个分区键最多20亿列值。使用虚拟分区键时,您将使用添加的每个值接近此限制。
您的数据将全部存储在同一个分区中,这将创建一个"热点" (群集中的大型数据分组)。这意味着您的数据模型将立即取消Cassandra的主要优势之一......数据分发。这也会使负载平衡变得复杂(相同的节点和范围将继续为您的所有请求提供服务)。
我可以看到您的模型是围绕SELECT *
查询设计的。当你可以给它特定的查询键时,Cassandra效果最好。未绑定的SELECT *
查询(没有WHERE子句的查询)不适合使用Cassandra,因为它们可能导致超时(随着数据的增长)。
从阅读问题开始,我知道你会说你只用了1000行。您的数据集不会超过这1000行,所以您不会遇到我提到的任何障碍。
那么我不得不怀疑,你为什么要使用Cassandra?作为一个Cassandra MVP,这是一个我不经常问的问题。但是你没有一个特别大的数据集(这就是Cassandra的设计用途)。依赖这一事实作为使用产品错误的理由并不是最佳解决方案。
老实说,我建议您为自己节省一些复杂性,并使用RDBMS代替。这将比Cassandra更好地适合您的用例。然后,您可以按照您希望的任何字段进行更新和排序。