列式NoSQL和文档导向的NoSQL有何不同?

112

我读过的NoSQL数据库有三种类型:键值对、列式和文档型。

键值对很直接 - 一个键对应一个值。

我看到文档型数据库被描述成类似于键值对,但值可以是一个结构,比如JSON对象。每个“文档”可以具有部分、全部或没有与另一个相同的键。

列式数据库似乎非常像文档型数据库,因为你不需要指定一个结构。

那么这两者之间的区别是什么,为什么要使用其中之一?

我特别看了MongoDB和Cassandra。我基本上需要一个可以动态更改结构但不影响其他值的结构。同时,我需要能够搜索/过滤特定的键并生成报告。对于CAP,AP对我来说最重要。数据可以“最终”在节点之间同步,只要没有冲突或数据丢失即可。每个用户都将拥有自己的“表格”。

4个回答

68

主要的区别在于文档式数据库(例如MongoDB和CouchDB)允许任意复杂的文档,即子文档内嵌子文档,包含文档的列表等等。而列式数据库(例如Cassandra和HBase)只允许固定格式,例如严格的一级或二级字典。


在这种情况下,Mongo(文档)可以做Cassandra(列)能做的事情。那么为什么还需要列呢? - sanjay patel
6
使用不同设计方式的存储引擎之间需要进行权衡,使用基于列的设计可以使存储引擎比基于文档的存储引擎更加高效。如果MongoDB文档增长,则必须在磁盘上重写整个文档,但Cassandra则不需要进行这种操作(当然,这只是一个简化的描述,其中有很多细节)。这使得Cassandra在写入方面更快。 - Theo
2
更正命名和理解:Cassandra和Hbase是列“族”存储,而不是列“导向”存储(也称为列存储)。CF按行存储数据(=面向行的存储),CO按列存储数据。参考:https://community.datastax.com/answers/6244/view.html - Vyshnav Ramesh Thrissur

48
在Cassandra中,每一行(由一个键定位)包含一个或多个“列”。列本身又是键值对。列名不需要预先定义,即结构不是固定的。一行中的列按其键(名称)的排序顺序存储。
在某些情况下,您可能会在一行中拥有非常大量的列(例如作为索引以启用特定类型的查询)。Cassandra可以高效地处理这样大的结构,并且您可以检索特定范围的列。
还有一个更深层次的结构(不太常用),称为超级列,其中一个列包含嵌套的子列。
你可以把整体结构看作是一个嵌套的哈希表/字典,有2或3级键。 普通列族:
row
    col  col  col ...
    val  val  val ...

超级列族:

row
      supercol                      supercol                     ...
          (sub)col  (sub)col  ...       (sub)col  (sub)col  ...
           val       val      ...        val       val      ...

还有更高级别的结构 - 列族和键空间 - 可以用于分割或组合您的数据。

另请参阅此问题:Cassandra: 什么是子列

或者从http://wiki.apache.org/cassandra/ArticlesAndPresentations链接的数据建模。

关于与面向文档的数据库的比较 - 后者通常插入整个文档(通常是JSON),而在Cassandra中,您可以访问单个列或超列,并单独更新它们,即它们在不同的粒度级别上工作。每个列都有自己单独的时间戳/版本(用于跨分布式集群协调更新)。

Cassandra列值只是字节,但可以被类型化为ASCII、UTF8文本、数字、日期等。

当然,您可以通过插入包含JSON的列来将Cassandra用作原始文档存储,但您不会获得真正面向文档存储的所有功能。


6
列族类似于表格。一行就像表格中的一行。列有点像数据库中的列,但它们可以动态定义,因此在某些情况下,您可能会有一个非常稀疏地填充的表格,或者每行可能填充不同的列。 - DNA
1
这取决于数据库。在MongoDB(面向文档)中,您还可以更新每个单独的键。 - David Raab
1
如果这是真的,那么MongoDB如何被定义为面向文档的数据库,而Cassandra则是面向列的?它们有什么不同之处? - Luke
3
列式存储看起来很像无模式关系型数据库,但除了它松散的结构外,主要区别在于它不是关系型的。 - user327961
1
@user327961 但是MongoDB也像一个无模式的关系型数据库,它也不是关系型的。 - huggie
显示剩余2条评论

36
在"插入"方面,使用关系型数据库术语来说,基于文档的系统更加一致和直接。需要注意的是,Cassandra通过仲裁(Quorum)的概念能够实现一致性,但这并不适用于所有基于列的系统,而且会降低可用性。在一个读多写少的系统中,建议选择MongoDB。如果您总是计划读取对象的整个结构,请考虑使用它。基于文档的系统旨在返回整个文档,而在返回整行的部分数据时并不十分强大。
与之相比,像Cassandra这样的基于列的系统在“更新”方面要比基于文档的系统优秀得多。您可以更改列的值,而无需读取包含该值的行。写入实际上不需要在同一台服务器上完成,一行可以包含在多个文件或多个服务器上。对于快速发展的大型数据系统,请选择Cassandra。如果您计划每个键有非常大的数据块,并且不需要在每次查询时加载所有数据块,请也考虑使用Cassandra。在"选择"方面,Cassandra允许您仅加载所需的列。
此外,需要考虑的是,MongoDB是用C++编写的,并且已经发布了第二个主要版本,而Cassandra需要在JVM上运行,其第一个主要版本仅在昨天发布了RC版(但0.X版本已经被一些主要公司投入生产使用)。
另一方面,Cassandra的设计部分基于Amazon Dynamo,并且从核心上构建为高可用性解决方案,但这与基于列的格式无关。MongoDB也可以扩展到多台服务器,但不如Cassandra那样优雅。

1
一款软件使用C++编写与使用Java编写有何不同? - Nayuki
@Nayuki 现在,我知道有高争用负载的情况下,Java内存管理模型的懒惰垃圾回收理论上会优于C++的“手动”管理模型,但一般来说,只要禁用异常和RTTI,编写等效程序以在C++中超越Java通常不是很困难。如果您充分利用无栈协程和可恢复函数,那么,我个人还没有看到Java能够击败我的C++。 - patrickjp93

3
我认为主要区别在于这些数据库类型物理存储数据的方式不同。
使用列类型,数据通过列来存储,这可以使得对特定列进行高效的聚合操作/查询。
使用文档类型,整个文档在逻辑上存储在一个地方,并且通常作为一个整体检索(无法对“列” /“字段”进行有效的聚合操作)。
令人困惑的是,宽列“行”可以轻松地表示为文档,但是它们以不同的方式存储,并针对不同的目的进行了优化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接