Cassandra数据建模少于1000条记录来适应一行



我们有一些由生成的UUID唯一标识的实体。我们需要支持按名称查找查询。我们还需要支持按名称排序。

我们知道不超过1000个这种类型的实体可以完美地放在一行中。硬编码主键,使用名称作为集群键,使用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

Name是可编辑字段,它可能很少被更改(有人可能会打错字,或者学校可能会更改名称),但它可以更改。实现这一目标的最佳方式是什么?删除插入内批(LTE可以应用于同一行与条件子句)?

是的,对于这样小的数据集,这是一个很好的方法。仅仅因为Cassandra可以跨多个节点对大型数据集进行分区,并不意味着您需要对每个表都使用该功能。通过对分区键使用常量,您告诉Cassandra您希望将数据存储在一个节点上,您可以快速地按顺序访问它。关系数据库总是作用于单个节点上的数据,所以这真的不是什么不寻常的事情。

为了安全起见,您可能希望使用大于1的复制因子,以便单个分区至少有两个副本。这样,即使存储数据的一个节点发生故障,您也不会失去对数据的访问权限。

这种方法可能会导致问题,如果你期望有很多客户端(即数千个客户端)经常读写这个表,因为它可能成为一个热点。只有1000条记录,你可以通过设置表缓存所有的键和行来保持所有的行缓存在内存中。

你可能找不到很多这样做的例子,因为人们转向Cassandra是为了支持大型数据集,他们希望通过使用多个分区来获得可伸缩性。这些例子都是这样的

这是可行的解决方案吗?是否存在我们没有看到的问题?我没有看到任何关于Cassandra数据建模的硬编码主键的例子,可能是因为这个原因,所以我们怀疑这个解决方案。

我在今年早些时候的文章:We Shall Have Order!中简要介绍了这种类型的建模解决方案。这就是所谓的"虚拟键",其中每行都有相同的分区键。这是一种快捷方式,允许您通过聚集列轻松地对所有行(在未绑定的SELECT *上)进行排序。

这个解决方案的问题:

  • Cassandra允许每个分区键最多20亿个列值。当使用虚拟分区键时,您添加的每个值都将接近此限制。

  • 您的数据将全部存储在同一个分区中,这将在您的集群中创建一个"热点"(大型数据组)。这意味着您的数据模型将立即使Cassandra的主要优点之一失效……数据分布。这也会使负载平衡复杂化(相同的节点和范围将继续服务您的所有请求)。

  • 我可以看到你的模型是围绕SELECT *查询设计的。当您可以为Cassandra提供特定的查询键时,Cassandra工作得最好。未绑定的SELECT *查询(没有WHERE子句的查询)不是Cassandra的好主意,因为它们可能导致超时(随着数据的增长)。

通过阅读你的问题,我知道你会说你只使用它1000行。你的数据集不会超过这1000行,所以你不会遇到我提到的任何障碍。

所以我不得不想,你为什么要用Cassandra?作为卡桑德拉的MVP,这是一个我不常问的问题。但是你没有一个特别大的数据集(这是Cassandra设计的工作)。依赖于这个事实作为错误使用产品的理由并不是最好的解决方案。

老实说,我建议您为自己节省一些复杂性,并使用RDBMS。这将比Cassandra更适合您的用例。然后你可以根据你想要的字段来更新和排序。

最新更新