Cassandra 具有简单数据库示例的数据模型
尽管 Cassandra 查询语言类似于 SQL 语言,它们的数据建模方法完全不同。
In Cassandra,糟糕的数据模型会降低性能,尤其是当用户尝试在 Cassandra。最好记住下面详述的几条规则。
Cassandra 数据模型规则
In Cassandra,写入并不昂贵。 Cassandra 不支持连接、分组、OR 子句、聚合等。因此,您必须以完全可检索的方式存储数据。因此,在对数据进行建模时,必须牢记这些规则 Cassandra.
最大化写入次数
In Cassandra,写入非常便宜。 Cassandra 该算法针对高写入性能进行了优化。因此,为了获得更好的读取性能和数据可用性,请尽量增加写入次数。数据写入和数据读取之间存在权衡。所以,请通过增加数据写入次数来优化数据读取性能。
最大化数据复制
数据非规范化和数据重复事实上 Cassandra磁盘空间并不比内存、CPU 处理和 IO 操作更昂贵。 Cassandra 是一个分布式数据库,因此数据复制提供了即时数据可用性并且没有单点故障。
Cassandra 数据建模目标
在建模数据时,您应该有以下目标 Cassandra:
均匀分布数据 Cluster
您希望每个节点上的数据量相等 Cassandra Cluster数据根据分区键(主键的第一部分)分布到不同的节点。因此,为了使数据均匀分布在集群中,请尽量选择基数较高的列作为分区键。
最小化查询数据时读取的分区数量
分区是一组具有相同分区键的记录。当发出读取查询时,它会从不同的分区的不同节点收集数据。
如果有多个分区,则需要访问所有这些分区来收集查询数据。
这并不意味着不应该创建分区。如果你的数据量非常大,就不能把如此庞大的数据保存在单个分区上,否则单个分区的运行速度会变慢。
因此请尽量选择平衡的分区数量。
良好的主键 Cassandra
以上两个目标都归结为一个决定,因此下面的两个模式显示了同一个表,一个是较差的键,另一个是较好的键。
让我们举个例子,找出哪个主键比较好。
这是 MusicPlaylist 表格。
CREATE TABLE MusicPlaylist ( SongId int, SongName text, Year int, Singer text, PRIMARY KEY (SongId, SongName) );
在上面的例子中,表 MusicPlaylist,
- SongId 是分区键,并且
- SongName 是聚类列
- 数据将基于歌曲名称进行聚类。每个歌曲 ID 只创建一个分区,由于每首歌都有一个唯一的标识符,因此每个分区只包含一行数据。
由于主键不好,该数据模型的数据检索将会很慢。
这是另一个表 MusicPlaylist。
CREATE TABLE MusicPlaylist ( SongId int, SongName text, Year int, Singer text, PRIMARY KEY ((SongId, Year), SongName) );
在上面的例子中,表 MusicPlaylist,
- SongId 和 Year 是分区键,
- SongName 是聚类列。
- 数据将根据 SongName 进行聚类。在此表中,每年将创建一个新分区。该年的所有歌曲都将位于同一节点上。此主键对于数据非常有用。
通过这个数据模型,我们的数据检索将会很快。
在模型中 Cassandra
在对查询进行建模时应牢记以下几点:
确定要支持的查询
首先,确定您想要什么查询。
比如你需要吗?
- 加入
- 通过...分组
- 根据哪一列进行过滤等等。
根据您的查询创建表
根据您的查询创建表。创建一个满足您查询的表。尝试以需要读取最少数量的分区的方式创建一个表。
接下来的三节将这一原则应用于几乎每个模式中都存在的三种关系类型。
处理一对一关系 Cassandra
一对一关系是指两个表有一对一的对应关系。例如,学生只能注册一门课程,我想搜索某个学生注册了哪门课程。
因此在这种情况下,您的表格模式应该包含与该特定课程相对应的学生的所有详细信息,例如课程名称、学生学号、学生姓名等。

上图显示了用于查询的单个表,因为一个学生只能对应一门课程。
CREATE TABLE Student_Course ( Student_rollno int PRIMARY KEY, Student_name text, Course_name text );
因为 Student_rollno 是分区键,所以按学号查找只会读取一个分区。
处理一对多关系 Cassandra
一对多关系是指两个表之间存在一对多的对应关系。
例如,一门课程可以有很多学生学习。我想搜索正在学习特定课程的所有学生。
因此,通过查询课程名称,我将获得许多正在学习特定课程的学生姓名。

这里,课程名称成为分区键,以便课程中的每个学生都位于同一个分区中,学号成为聚类列,以便每个学生保持为不同的行。
CREATE TABLE Student_Course ( Course_name text, Student_rollno int, Student_name text, PRIMARY KEY (Course_name, Student_rollno) );
我可以通过以下查询检索特定课程的所有学生。
SELECT * FROM Student_Course WHERE Course_name = 'Course Name';
处理多对多关系 Cassandra
多对多关系意味着两个表之间存在多对多的对应关系。
例如,一门课程可以由多位学生学习,一位学生也可以学习多门课程。

我想要搜索正在学习特定课程的所有学生。另外,我想要搜索特定学生正在学习的所有课程。
所以,在这种情况下,我会有两个表,也就是把问题分成两种情况。这是对重复规则最清晰的说明:相同的事实被写入两次,以便每个查询读取一个分区。
首先,我将创建一个表格,您可以通过该表格找到特定学生的课程。
CREATE TABLE Student_Course ( Student_rollno int, Course_name text, Student_name text, PRIMARY KEY (Student_rollno, Course_name) );
我可以通过以下查询找到特定学生的所有课程。
SELECT * FROM Student_Course WHERE Student_rollno = 101;
其次,我将创建一个表格,通过该表格您可以找到有多少名学生正在学习某一门课程。
CREATE TABLE Course_Student ( Course_name text, Student_rollno int, Student_name text, PRIMARY KEY (Course_name, Student_rollno) );
我可以通过以下查询找到特定课程的学生。
SELECT * FROM Course_Student WHERE Course_name = 'Cassandra';
当学生加入课程时,必须同时写入这两个表,通常在单个日志批处理中写入,以便两个副本保持同步。
相当常见 Cassandra 数据建模错误
大多数糟糕的模式都会重复出现相同的几个错误,而且每个 trac这又回到了关系设计中沿袭下来的习惯。
- 无界分区: 选择国家/地区名称等分区键会将数百万行数据放入一个分区中。添加时间范围(例如,国家/地区,月份)可以使分区大小保持在合理范围内。
- 极低基数键: 分区键如果只有少数几个可能的值(例如状态标志),则会将所有流量集中在少数几个节点上,而其余节点则处于空闲状态。
- 使用 ALLOW FILTERING 使查询生效: 它会扫描每个分区,从而隐藏建模问题。如果查询需要,则模式需要添加另一张表。
- 使用实体建模而非查询: 先建立学生表和课程表,然后再尝试在应用程序中将它们合并,就违背了设计的初衷。
- 频繁删除和覆盖: 每次删除操作都会写入一个墓碑标记,必须先读取并跳过该标记,直到压缩操作将其移除,这会减慢热点分区上的读取速度。
避免这些情况,可以使模式与本页顶部所述的规则以及下面总结的关系对比保持一致。
RDBMS 和 Cassandra 资料建模
| RDBMS | Cassandra |
|---|---|
| 以规范化形式存储数据 | 以非规范化形式存储数据 |
| 旧式数据库管理系统;结构化数据 | 宽行存储,动态;结构化和非结构化数据 |
| 模式是围绕实体及其关系设计的。 | 模式是围绕应用程序将要运行的查询而设计的。 |
| 支持连接、GROUP BY 和任意 WHERE 子句。 | 不允许使用连接或任意过滤;查询必须与主键匹配。 |
| 一张表通常服务于许多不同的查询 | 一张表通常服务于一个查询,因此数据会在多个表中重复出现。 |
| 通过外键强制执行引用完整性 | 不允许使用外键;重复表之间的一致性由应用程序负责。 |
这些模式决策在实践中得到应用。 Cassandra 表 和 键空间 教程。

