在互联网上阅读了几篇论文和文档,我发现了许多关于 Cassandra 数据模型的相互矛盾的信息。有许多人将其识别为面向列的数据库,其他人将其识别为面向行的数据库,然后将其定义为两者的混合方式。
根据我对 Cassandra 如何存储文件的了解,它使用 *-Index.db 文件访问 *-Data.db 文件的正确位置,其中存储了布隆过滤器、列索引,然后是所需的行。
在我看来,这是严格面向行的。有什么我想念的吗?
在互联网上阅读了几篇论文和文档,我发现了许多关于 Cassandra 数据模型的相互矛盾的信息。有许多人将其识别为面向列的数据库,其他人将其识别为面向行的数据库,然后将其定义为两者的混合方式。
根据我对 Cassandra 如何存储文件的了解,它使用 *-Index.db 文件访问 *-Data.db 文件的正确位置,其中存储了布隆过滤器、列索引,然后是所需的行。
在我看来,这是严格面向行的。有什么我想念的吗?
Cassandra 是一个分区的行存储。行被组织成具有所需主键的表。
分区意味着 Cassandra 可以在应用程序透明的情况下将您的数据分布在多台机器上。Cassandra 将在集群中添加和删除机器时自动重新分区。
行存储意味着像关系数据库一样,Cassandra 按行和列组织数据。
面向列或列式数据库按列存储在磁盘上。
例如Bonuses
:表表
ID Last First Bonus
1 Doe John 8000
2 Smith Jane 4000
3 Beck Sam 1000
在面向行的数据库管理系统中,数据将像这样存储: 1,Doe,John,8000;2,Smith,Jane,4000;3,Beck,Sam,1000;
在面向列的数据库管理系统中,数据将像这样存储:
1,2,3;Doe,Smith,Beck;John,Jane,Sam;8000,4000,1000;
Cassandra 基本上是一个列式存储
Cassandra 会将上述数据存储为,
"Bonuses" : {
row1 : { "ID":1, "Last":"Doe", "First":"John", "Bonus":8000},
row2 : { "ID":2, "Last":"Smith", "First":"Jane", "Bonus":4000}
...
}
此外,每行中的列数不必相同。一行可以有 100 列,而下一行只能有 1 列。
阅读本文了解更多详情。
是的,“面向列”的术语有点令人困惑。
Cassandra 中的模型是行包含列。要访问最小的数据单元(一列),您必须首先指定行名(键),然后是列名。
因此,在一个名为的列族中,Fruit
您可以具有类似于以下示例的结构(有 2 行),其中水果类型是行键,并且每个列都有一个名称和值。
apple -> colour weight price variety
"red" 100 40 "Cox"
orange -> colour weight price origin
"orange" 120 50 "Spain"
与基于表的关系数据库的一个区别是可以随时省略列(橙色没有变化),或随时添加任意列(橙色有来源)。您仍然可以将上面的数据想象成一个表格,尽管它是一个稀疏的表格,其中许多值可能为空。
但是,“面向列”的模型也可以用于列表和时间序列,其中每个列名都是唯一的(这里我们只有一行,但我们可以有数千或数百万列):
temperature -> 2012-09-01 2012-09-02 2012-09-03 ...
40 41 39 ...
这与关系模型完全不同,在关系模型中,必须将时间序列的条目建模为rows
not columns
。这种类型的用法通常被称为“宽行”。
你们都提出了很好的观点,这可能会令人困惑。在示例中
apple -> colour weight price variety
"red" 100 40 "Cox"
apple 是键值,column 是数据,包含所有 4 个数据项。从所描述的情况来看,听起来所有 4 个数据项都作为单个对象存储在一起,然后由应用程序解析以提取所需的值。因此,从 IO 的角度来看,我需要阅读整个对象。恕我直言,这本质上是基于行(或对象)的,而不是基于列的。
基于列的存储在仓储中变得很流行,因为它为全表扫描 (DW) 提供了极大的压缩和减少了 IO,但是当您需要拉取每一列时,它会以增加 OLTP 的 IO 为代价(选择 *)。大多数查询不需要每一列,并且由于压缩,对于仅针对几列的全表扫描,IO 可以大大减少。让我举个例子
apple -> colour weight price variety
"red" 100 40 "Cox"
grape -> colour weight price variety
"red" 100 40 "Cox"
我们有两种不同的水果,但都有一种颜色 = 红色。如果我们将颜色与重量、价格和品种分开存储在单独的磁盘页面(块)中,那么唯一存储的就是颜色,那么当我们压缩页面时,由于大量的重复数据删除,我们可以实现极端压缩。我们可以存储 10,000 种颜色,而不是在一个页面中存储 100 行(假设)。现在要读取红色的所有内容,它可能是 1 个 IO 而不是数千个 IO,这对仓储和分析非常有用,但如果我需要更新整行,则对 OLTP 不利,因为该行可能有数百列和一个更新(或插入)可能需要数百个 IO。
除非我遗漏了一些我不会称之为基于柱状的东西,否则我会称之为基于对象。目前尚不清楚对象在磁盘上的排列方式。多个对象是否放置在同一个磁盘页面中?有什么方法可以确保具有相同元数据的对象放在一起?一种水果可能包含与另一种水果不同的数据,因为它只是元数据或 xml 或您想要存储在对象本身中的任何内容,有没有办法确保将某些匹配的水果类型存储在一起以提高效率?
拉里
我遇到的最明确的术语是宽列商店。
它是一种二维键值存储,您使用行键和列键来访问数据。
该模型与关系模型(面向行和面向列)的主要区别在于列信息是数据的一部分。
这意味着数据可以是稀疏的。这意味着不同的行不需要共享相同的列名或列数。这启用了半结构化数据或无模式表。
您可以将宽列存储视为可以容纳无限数量的列的表,因此是宽的。
这里有几个链接来支持这一点:
Column Family 并不意味着它是面向列的。Cassandra 是列族,但不是面向列的。它将行及其所有列族存储在一起。
Hbase 是列族,并且以面向列的方式存储列族。不同的列族分别存储在一个节点中,甚至可以驻留在不同的节点中。
IMO 这是用于 Cassandra 的错误术语。相反,将其称为行分区存储更为合适。让我为您提供一些详细信息:
主键、分区键、聚类列和数据列:
每个表都必须有一个具有唯一约束的主键。
Primary Key = Partition key + Clustering Columns
# Example
Primary Key: ((col1, col2), col3, col4) # primary key uniquely identifies a row
# we need to choose its components partition key
# and clustering columns so that each row can be
# uniquely identified
Partition Key: (col1, col2) # decides on which node to store the data
# partitioning key is mandatory, and it
# can be made up of one column or multiple
Clustering Columns: col3, col4 # decides arrangement within a partition
# clustering columns are optional
分区键是主键的第一个组成部分。其散列值用于确定存储数据的节点。分区键可以是由多列组成的复合键。我们想要几乎相等的数据分布,我们在选择主键时牢记这一点。
主键中分区键之后列出的任何字段都称为聚类列。这些在分区内按升序存储数据。聚类列组件还有助于确保每行的主键是唯一的。
您可以使用任意数量的聚类列。不能在 SELECT 语句中乱序使用集群列。您可以选择在 SELECT 语句中省略使用聚类列。没关系。请记住在使用 SELECT 语句时按顺序起诉他们。但请注意,在您的 CQL 查询中,如果您没有使用其他定义的集群列,则不能尝试访问列或集群列。例如,如果主键是(year, artist_name, album_name)
并且您想city
在查询的WHERE
子句中使用列,那么只有当您的WHERE
子句使用作为主键一部分的所有列时,您才能使用它。
代币:
Cassandra 使用令牌来确定哪个节点拥有什么数据。令牌是一个 64 位整数,Cassandra 将这些令牌的范围分配给节点,以便每个可能的令牌都归一个节点所有。向集群中添加更多节点或删除旧节点会导致在节点之间重新分配这些令牌。
行的分区键用于使用给定的分区器(用于计算分区键的令牌的哈希函数)计算令牌,以确定哪个节点拥有该行。
Cassandra 是行分区存储:
行是 Cassandra 中存储相关数据的最小单位。
不要把 Cassandra 的列族(也就是表)看成是 RDBMS 表,而是把它看成 a dict
of adict
(这里dict
是类似于 Python 的数据结构OrderedDict
):
dict
由行键(主键)键控:这决定了哪个分区和分区中的哪一行dict
dict
名作为键的数据dict
都是有序的(按键)并排序:外部dict
按主键排序此模型允许您随时省略列或添加任意列,因为它允许您为不同的行拥有不同的数据列。
Cassandra 有一个列族(table)的概念,最初来自 BigTable。但是,正如您所提到的,将它们称为面向列的确实是一种误导。在每个列族中,它们将一行中的所有列连同一个行键一起存储,并且它们不使用列压缩。因此,Bigtable 模型仍然主要是面向行的。