我很难弄清楚如何在多个表之间维护属性更新以确保数据一致性。
例如,假设我在演员和粉丝之间有很多对很多的关系。一个粉丝可以支持很多演员,一个演员也有很多粉丝。我制作了几个表格来支持我的查询
CREATE TABLE fans (
fan_id uuid,
fan_attr_1 int,
fan_attr_2 int
PRIMARY KEY ((fan_id))
)
CREATE TABLE actors (
actor_id uuid,
actor_attr_1 int,
actor_attr_2 int
PRIMARY KEY ((actor_id))
)
CREATE TABLE actors_by_fan (
fan_id uuid,
actor_id uuid,
actor_attr_1 int,
actor_attr_2 int
PRIMARY KEY (fan_id, actor_id)
)
CREATE TABLE fans_by_actor (
actor_id uuid,
fan_id uuid,
fan_attr_1 int,
fan_attr_2 int
PRIMARY KEY (actor_id, fan_id)
)
假设我是一个粉丝,我在我的设置页面上,我想将我的fan_attr_1
更改为不同的值。
在fans
表上,我可以很好地更新我的属性,因为应用程序知道我的fan_id,并且可以键入它。
但是,如果不首先查询绑定到风扇的actor_id,我就无法在fans_by_actor
上更改我的fan_attr_1
。
每当您想要更新fans
或actors
的任何属性时,都会出现此问题。
我试着在网上寻找遇到类似问题的人,但我找不到他们。例如,在Datastax的数据建模课程中,他们以多对多的关系使用演员和视频的示例,其中他们有表actors_by_video
和videos_by_actor
。与我查阅的其他在线资源一样,本课程讨论了在查询后对表进行建模,但没有深入研究如何保持数据完整性。在actors_by_video
表中,如果我想更改参与者的属性,会发生什么情况?不必遍历actors_by_video
的每一行就可以找到包含actor的分区并更新属性吗?这听起来效率很低。另一种选择是事先查找视频id,但我在其他地方读到,在Cassandra中,先读后写是一种反模式。
从数据建模的角度或从CQL的角度来看,解决这个问题的最佳方法是什么?
编辑:-固定句子存根-增加了背景和先前的研究
数据建模
Cassandra不是关系数据库,在DataModeling上需要遵循某些基本规则,在高层,我们的数据模型需要遵循以下目标。
1) 在集群中均匀分布数据
2) 最小化读取的分区数
此外,我们应该选择一个大表,而不是将其分解为多个表并添加表之间的关系。在这种方法中,将出现重复记录。复制记录并不是一项成本更高的操作,因为它只需要多一点磁盘空间,而不是CPU、内存、磁盘IOP或网络。
请注意,列关键字名称和值有大小限制。列键(和行键)的最大大小为64KB。最大列值大小为2 GB。但是,由于没有流,并且在请求时会在堆内存中获取整个值,因此将大小限制为几个MB。
更多信息:
http://www.datastax.com/dev/blog/basic-rules-of-cassandra-data-modeling
http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/
http://www.ebaytechblog.com/2012/08/14/cassandra-data-modeling-best-practices-part-2/
https://docs.datastax.com/en/cql/3.1/cql/cql_reference/refLimits.html
CQL
可以使用批处理视图或物化视图来维护跨表的一致性。物化视图可从版本3.0 获得
请参阅
如何确保Cassandra中不同表上的数据一致性?
我更喜欢更改数据模型并进行设计相应地用于我们的查询,如果可能的话,将其作为一个大表。
希望它能有所帮助!
物化视图可能是最佳选择:
CREATE MATERIALIZED VIEW actors_by_fan
AS SELECT fan_id, actor_id, actor_attr_1, actor_attr_2
FROM fans
PRIMARY KEY (fan_id, actor_id);
CREATE MATERIALIZED VIEW fans_by_actor
AS SELECT actor_id, fan_id, fan_attr_1, fan_attr_2
FROM actors
PRIMARY KEY (actor_id, fan_id);
在3.0之前的版本中,创建辅助索引并评估其性能是否可接受。稍后,在升级到3.x之后,只需删除二级索引并创建物化视图。
解决此类问题的方法是手动更新所有更改的记录。
由于您不能使用物化视图,为了更新数据上的fan_attr_1
,您需要:
- 通过发出
UPDATE fan ... WHERE fan_id = xxx
来更新fan
表 - 通过发出
SELECT actor_id ... WHERE fan_id = xxx
从actors_by_fan
中选择所有actor_id
- 通过发出
UPDATE fans_by_actor ... WHERE actor_id IN (...)
更新fans_by_actor
表中的所有对应行,或者在actor_id
上循环并运行每个更新异步
只要在步骤2中有少量的actor_id
,比如说少于20,就可以对所有查询进行分组,并通过在单个BATCH
中运行它们来保持表之间的强一致性。您需要以其他方式保证表之间的一致性。
这可能听起来效率很低,但我不认为还有其他更聪明的解决方案。顺便说一下,您正在发出一次读取(步骤2)和多次写入(步骤1和步骤3)。这不会是世界末日,尤其是如果你不经常更改属性(例如每10毫秒)。