现今云计算的从业人员对NoSQL一词并不感到陌生,虽然很多技术人员都长期从事关系数据库的工作,但现在他们对NoSQL技术充满期待。对于企业来说,从关系型数据库到NoSQL数据库转变绝对是个需要深思熟虑的大改变。这涉及的不仅是软件的变化,更多的是对于数据存储上观念性的变化。
CouchDB专家兼作者Bradley Holt认为NoSQL并不是反SQL的运动,为对应的工作选择最恰当的工具才是正确的模式。
大多数非关系数据库都具有快速和可伸缩的特性。通过放弃关系存储模型和架构,关系数据库便可脱离由紧密结合的架构所带来对其施加的限制。应用程序也无需再链接数据库内表中的数据。
MongoDB和CouchDB以及RavenDB(RavenDB是基于Mocrosoft .NET Framework编写的)等文档数据库除了某些特定的转换外,通常都是通过HTTP为其提供数据,然后将数据存储为JSON(JavaScript Object Notation)格式的文档,并提供多种语言的API接口。这三款开源的文档数据库都将简洁、速度和可伸缩性作为其设计的重要指标。RavenDB的创建者Ayende Rahien就表示“RavenDB的设计初衷就旨在快速写入并读取”。
NoSQL——关系数据库的有力补充
现今,NoSQL和文档数据库成为关系数据库的有力补充(而非替代品),同时提供了更多的选择。如果企业准备将数据迁移,那么选择NoSQL的重要标准就是要看CAP(Consistency、Availability和Partition Tolerance),也就是我们所说的一致性、可用性和分区容忍性。但CAP原则要求在分布式系统只能选择一致性、可用性和分区容忍性其中的两项。所以如果企业认为一致性是重要的那么关系数据库理应是优先选择的对象。
例如在银行等应用领域,一致性是非常重要的,这要求必须随时考虑每个数据块。而CAP原则中的可用性也不容忽视,某些领域的数据可用性要比等待所有交易数据收集齐全更为重要。最后在水平缩放时,分区容忍性对于文档数据库显得尤为关键。但MongoDB并不支持复杂的事务,只支持少量的原子操作,所以不适用于“转帐”等对事务和一致性要求很高的场合。这就要求需要一个关系数据库来对交易进行过高级别的控制。
文档数据库的关键特性
RESTful HTTP API
RESTful API设计就是为了消除创建松散耦合服务时的依赖关系,这也正是过去分布式体系结构的缺陷。虽然要映射到一些协议需要依赖于元数据的可用性以及方法等,但REST API的设计目标就是不依赖于任何通信协议。
众多NoSQL数据库都可通过RESTful的方式访问。这样可以通过URI的方式建立数据库连接,而查询和命令则通过HTTP实现。MongoDB和CouchDB都提供了特定语言的API接口,以便编写和执行查询、更新。但MongoDB的默认设置仍然是使用TCP与数据库进行连接。而RavenDB则具备基于.NET的客户端API,可简化与数据库的交互过程。
单个记录中的相关数据
大多数人都错误的认为非关系数据库是一种包含没有相对关系结构的记录的文件。而文档数据库中存储的数据包含形状数据——具有节点的树。数据库中的每个记录都是以文档形式存在的。并具备自我描述的功能,而不依赖于任何其他文档。
示例代码1:文档数据库(MongoDB)中的典型事例
{
"name" : "Jim",
"scores" : [ 75, 99, 87.2 ]
}
示例代码2 CouchDB示例
{
"Subject": "I like Plankton"
"Author": "Rusty"
"PostedDate": "5/23/2006"
"Tags": ["plankton", "baseball", "decisions"]
"Body": "I decided today that I don't like baseball. I like plankton."
}
示例代码3 包含字符串数据、数字和数组的简单结构。还可在对象内嵌入对象,以获得更复杂的文档结构。
{
"BlogPostTitle”: “LINQ Queries and RavenDB”,
"Date":"/Date(1266953391687+0200)/",
"Content":”Querying RavenDB is very familiar for .NET developers who are already
using LINQ for other purposes”,
"Comments":[
{
"CommentorName":"Julie",
"Date":"/Date(1266952919510+0200)/",
"Text":"Thanks for using something I already know how to
work with!",
"UserId":"users/203907"
},
]
}
唯一键
所有数据库都需要键。如果不提供键系统则会自动在内部创建一个键。键对于数据库的索引功能至关重要。自身域中要求有已知键,在上面的示例代码中存在对“users/203907”的引用。这正式RavenDB利用键值并允许用户定义文档间关系的方式。
以JSON格式存储数据
共同点都是使用JSON存储器数据。事实上,CouchDB和RavenDB(以及其他许多数据库)均采用JSON格式存储数据。MongoDB对JSON使用称之为“二进制JSON”(BSON)的转换,以便能够执行二进制序列化。BSON是数据的内部表现形式,从编程的角度看开发者不会发现有任何区别。托福答案
JSON的简洁性使其很容易将几乎所有语言的对象结构转换为JSON。 因此,开发者可在应用程序中定义对象,然后将其直接存储在数据库中。这使得开发人员不需要使用对象关系映射程序 (ORM) 不断在数据库架构和类/对象架构之间进行转换。托福答案
MongoDB BSON API的数据类型和约定列表添加了一种数据类型及其他一些数据类型,以便充实JSON中的可用内容。而在一个单元中存储和检索相关数据可提供显著的性能和可伸缩性的优势。数据库不必四处查找常用的相关的数据,因为数据都存储在相同的位置。
类型的集合
与数据库交互时,应用程序如何知道哪一项代表学生,哪一项代表书,以及哪一项代表博客文章? 数据库使用集合这一概念解决了这一问题。 对于与特定集合(如学生集合)关联的任何文档(无论其架构如何)都可在从该集合请求数据时对其进行检索。使用字段来指示类型也十分常见。这只是使搜索过程更加轻松,但哪些内容应进入集合,哪些不应进入集合,由开发者的应用程序决定。
架构灵活的数据库
前面介绍的“示例代码1”包含自己的架构。 每个记录负责自己的架构,甚至负责单个数据库或集合中包含的架构。并且一个学生记录并不需要与另一学生记录相匹配。开发者只需利用此灵活性来提高效率。例如,为什么存储 null 值? 您可以在属性(如“most_repeated class”)不具有值时执行以下操作:
"name" : "Jim",
"scores" : [ 75, 99, 87.2 ]
"name" : "Julie",
"scores" : [ 50, 40, 65 ],
"most_repeated_class" : "Time Management 101"
文档数据库和领域驱动开发
规划域类(可能成为数据库中的文档)时,开发者可查找通常最为独立的数据(例如具有其明细项的订单),并将其作为单个数据结构加以关注。在订购系统中,可能还有客户和产品。但或许会在不需要订单的客户信息的情况下访问该订单,并且可能会在不需要访问使用产品的订单的情况下使用该产品。这意味着,尽管会发现许多机会来包含独立数据结构(如具有其明细项的订单),但这并不表示在某些情形下可以不必或者不通过外键联接数据。
每个数据库都提供各种可用模式的指南,并为用户指明使用哪些模式可以获得最大成功。 例如MongoDB文档讨论称为“上级数组”的模式,它可加快在联接文档时对相关数据的访问速度。
在关系数据库中,重复数据是个错误。 对数据库进行标准化可确保不出现此情况。 使用NoSQL数据库(尤其是分发数据库)时,对数据进行逆规范化是必要且可接受的。
查询和更新
每个数据库都附带用于查询和更新的API。尽管它们可能不是核心API的一部分,但多语言API是通过加载项提供的。其他查询依赖预定义的视图和称为Map/Reduce的模式。此过程的映射阶段使用这些视图,并且各个数据库的映射职责是不同的。映射还使数据库能够跨多个处理器分发查询处理。化简阶段可获取映射查询(如果已分发,则为多个查询)的结果,并将数据聚合到要返回到客户端的结果中。
尽管CouchDB要求开发者通过预定义的Map/Reduce视图进行查询,但MongoDB(也使用视图和Map/Reduce)另外提供执行临时查询的功能。RavenDB允许使用预定义索引进行查询,但也支持临时查询,并将根据开发者的实际运行时查询自动为其创建索引。但在大多数时候,当不采用SQL数据库的已知架构和关系本质时,开发者会丢失的一个功能是执行临时查询的功能。通过严格控制查询,文档数据库能够实现其快速性能。
数据库变革
有许多非关系数据库都不属于NoSQL范畴。但既然这扇门已经敞开,就会鼓舞更多人去探索其可用的功能,并考虑如何改进它。