热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

DDIA第2章数据模型与查询语言

文章目录第2章数据模型与查询语言1关系模型与文档模型1.1NoSQL的诞生1.2对象-关系不匹配1.3多对一与多对多的关系1.4文档数据库是否在重演历史1.4.1网络模型1.4.2

文章目录

  • 第2章 数据模型与查询语言
    • 1 关系模型与文档模型
      • 1.1 NoSQL的诞生
      • 1.2 对象-关系不匹配
      • 1.3 多对一与多对多的关系
      • 1.4 文档数据库是否在重演历史
        • 1.4.1 网络模型
        • 1.4.2 关系模型
        • 1.4.3 文档数据库的比较
      • 1.5 关系数据库与文档数据库现状
        • 1.5.1 哪种数据模型的应用代码更简单?
        • 1.5.2 文档模型中的模型灵活性
        • 1.5.3 查询的数据局部性
        • 1.5.4 文档数据与关系数据库的融合
    • 2 数据查询语言
      • 2.1 Web上的声明式查询
      • 2.2 MapReduce查询
    • 3 图状数据模型
      • 3.1 图属性
      • 3.2 Cypher查询语言
      • 3.3 SQL中的图查询
      • 3.4 三元存储与SPARQL
        • 3.4.1 语义网
        • 3.4.2 RDF数据模型
        • 3.4.3 SPARQL查询语言
      • 3.5 Datalog基础
    • 小结


信息是激发创新的力量

        本章目标: 比较多种不同的数据模型和查询语言,讨论各自的适用场景。

第2章 数据模型与查询语言

        数据模型可能是开发软件最重要的部分,它们不仅对软件的编写方式,而且还对如何思考待解决的问题都有深远的影响。大多数应用程序是通过一层一层叠加数据模型来构建的。每一层都面临的关键问题是:如何将其用下一层来表示?

1 关系模型与文档模型

        早期的其他数据库迫使应用开发人员考虑数据的内部表示。关系模型的目标就是将实现细节隐藏在更简洁的接口后面。

1.1 NoSQL的诞生

        进入21世纪,NoSQL成为推翻关系模式主导地位的有一个竞争者。“NoSQL”这个名字是不恰当的,因为它其实并不代表具体的某些技术,它最初只是作为一个吸引人眼球的Twitter标签频频出现在2009年的开源、分布式以及非关系数据库的见面会上。尽管如此,这个称呼还是让人有所触动,并迅速传遍了网络创业社区。现在很多新兴的数据库系统总是会打上NoSQL的标签,而其含义也已经被逆向重新解释为“不仅仅是SQL”。
        不同的应用程序有着不同的需求,某个用例的最佳的技术选择未必合适另一个用例。因此,在可预见的将来,关系数据库可能仍将继续与各种非关系数据存储在一起使用,这种思路有时也被称为混合持久化。

1.2 对象-关系不匹配

        现在大多数应用开发都采用面向对象的编程语言,由于兼容性问题,普遍对SQL数据模型存在抱怨:如果数据存储在关系表中,那么应用层代码中的对象与表、行和列的数据库模型之间需要一个笨拙的转换层。 模型之间的脱离有时被称为阻抗失谐。ActiveRecord和Hibernate这样的对象-关系映射(ORM)框架则减少了此转换层所需的样板代码量,但是他们并不能完全隐藏两个模型之间的差异。
        为数据结构选取最适应的数据模型是很重要的。对于像简历这样的数据结构,它主要是一个自包含的文档(document),因此用JSON表示非常合适。用户简历到用户的职位、教育历史和联系信息的一对多关系,意味着数据存在树状结构,JSON表示将该树结构显示化。
        JSON表示比多表模式具有更好的局部性。如果要在关系模式中读取一份简历,那么要么执行多个查询(通过user_id查询每个表),要么在users表及其从属表之间执行混乱的多路联结。而对于JSON表示方法,所有的相关信息都在一个地方,一次查询就够了。

1.3 多对一与多对多的关系

        无论是存储ID还是文本字符串,都涉及内容重复的问题。当使用ID时,对人类有意义的信息(例如慈善这个词)只存储在一个地方,引用它的所有内容都使用ID(ID只在数据库中有意义)。当直接存储文本时,则使用它的每条记录中都保存了一份这样可读信息。简单来讲就是一个事物到底要不要单独作为一个实体抽象出来。 使用ID的好处是,因为它对人类没有任何直接意义,所以永远不需要直接改变:即使ID标识的信息发生了变化,它也可以保持不变。任何对人类有意义的东西都可能在将来某个时刻发生变更。如果这些信息被复制,那么所有的冗余副本也都需要更新。这会导致更多写入开销,并且存在数据不一致的风险(信息的一些副本被更新,而其他副本未更新)。消除这种重复正是数据库规范化的核心思想。
        这种数据规范化需要表达多对一的关系,并不是很适合文档模型。关系数据库支持联结操作,而文档数据库中,一对多的树状结构不需要联结,支持联结通常很弱。如果数据库本身不支持联结,则必须在应用应用程序代码中,通过对数据库进行多次查询来模拟联结。
        即使应用程序的初始版本非常适合采用无联结的文档模型,但随着应用支持越来越多的功能,数据也变得更加一体化。

1.4 文档数据库是否在重演历史

        层次模型与文档数据库使用的JSON模型有一些显著的相似之处。它将所有数据标识为嵌套在记录中的记录(树),与JSON结构非常相似。
        和文档数据库类似,IMS可以很好地支持一对多关系,但是它支持多对多关系则有些困难,而且不支持联结。开发人员必须决定是复制(反规范化)多份数据,还是手动解析记录之间的引用。20世纪六七十年代的这些问题与开发人员今天遇到的文档数据库的问题非常相似。

1.4.1 网络模型

        CODASYL模型是层次数据库的推广。在层次模型的树结构中,每个记录只有一个父节点;而在网络模型中,一个记录可能有多个父节点。
        在网络模型中,记录之间的链接不是外键,更像是编程语言中的指针(会存储在磁盘上)。访问记录的唯一方法是选择一条始于根记录的路径,并沿着相关链接依次访问。这条链接链条也因此被称为访问路径。最大的问题在于它们使查询和更新数据库变得异常复杂而没有灵活性。无论是层次模型还是网络模型,如果脱离数据的访问路径,那么将寸步难行。

1.4.2 关系模型

        在关系数据库中,查询优化器自动决定以何种顺序执行查询,以及使用哪些索引。这些选择实际上等价于“访问路径”,但最大的区别在于它们时由查询优化器自动生成的,而不是由应用开发人员所维护,因此不用过多地考虑它们。关系模型使得应用程序添加新功能变得非常容易。
        关系数据库的查询优化器称得上是一个复杂的怪兽,研究开发人员多年来持续投入,花费巨大。不管怎样,关系模型的一个核心要点是:只需构建一次查询优化器,然后使用该数据库的所有应用程序都可以从中受益。如果没有查询优化器,那么为特定查询手动编写访问路径比编写通用优化器更容易,但从长久来看,通用解决方案更胜一筹。

1.4.3 文档数据库的比较

        文档数据库是某种方式的层次模型:即在其父记录中保存了嵌套记录(一对多关系),而不是存储在单独的表中。
        但是,在表示多对一和多对多的关系时,关系数据库和文档数据库并没有根本的不同:在这两种情况下,相关项都由唯一的标识符引用,该标识符在关系模式中被称为外键,在文档模型中被称为文档引用。标识符可以查询时通过联结操作或相关后续查询来解析。迄今为止,文档数据库并未遵循CODASYL标准。

1.5 关系数据库与文档数据库现状

        比较两者时间,需要考虑很多方面的差异,包括容错性和并发处理。
        支持文档数据模型的主要论点是模式灵活性,由于局部性而带来较好的性能,对于某些应用来说,它更接近与应用程序所使用的数据结构。关系模型则强在联结操作、多对一和多对多关系更简洁的表达上,与文档模型抗衡。

1.5.1 哪种数据模型的应用代码更简单?

        通常无法一概而论哪种数据模型的应用代码更简单。这主要取决于数据项之间的关系类型。对于高度关联的数据,文档类型不太适合,关系模型可以胜任,而图模型则是最为自然的。

1.5.2 文档模型中的模型灵活性

        大多数文档数据库,以及关系数据库中的JSON支持,都不会对文档中的数据强制执行任何模式。关系数据库中的XML通常支持带有可选的模式验证功能。没有模式意味着可以将任意的键-值添加到文档中,并且在读取时,客户端无法保证文档可能包含哪些字段。
        文档数据库有时被称为无模式,但这具有误导性,因为读数据的代码通常采用某种结构因而存在某些隐形模式,而不是由数据库强制执行。更准确的术语应该是读时模式(数据的结构是隐式的,只有在读取时才解释),与写时模式(关系数据库的一种传统方法,模式是显示的,并且数据库确保数据写入时都必须遵循)相对应。
        当应用程序需要改变数据格式时,这些方法之间的差异就变得尤其明显。如果集合中的项由于某种原因(例如数据异构),并不都有相同的结构,例如:

  • 有许多不同类型的对象,将每种类型的对象都保存在各自的表中不太现实
  • 数据的结构由无法控制的外部系统所决定,而且可能随时改变

        在这些情况下,模式带来的损害大于它所能提供的帮助,无模式文档可能是更自然的数据模型。但是,当所有记录都有相同结构时,模式则是记录和确保这种结构的有效机制。

1.5.3 查询的数据局部性

        局部性优势仅适用需要同时访问文档大部分内容的场景。只访问加载了整个文档的一小部分,修改文档时增加了文档的大小,这些性能方面的不利因素大大限制了文档数据库的适用场景。
        值得指出的是,将相关数据归为一组的局部性想法并不仅见于文档模型。例如,Google的Spanner数据库在关系数据模型中提供了相同的局部性,支持模式声明某些表的行应该在父表内交错(嵌套)。Oracle支持类似的操作,称为“多表索引集群表”特性,Bigtable数据模型(用于Cassandra和HBase)中的列族概念类似。

1.5.4 文档数据与关系数据库的融合

        随着时间的推移,似乎关系数据库与文档数据库变得越来越相近,或许这是一件好事:数据模型可以相互补充。如果数据库能够很好处理文档类数据,还能对其执行关系查询,那么应用程序可以使用最符合其需求的功能的组合。
        融合关系模型与文档模型是未来数据库发展的一条很好的途径。

2 数据查询语言

        当关系模型是初被引入时,就包含了查询数据的新方法:SQL是一种声明式查询语言,而IMS和CODASYL则是命令式。这种差别意味着什么呢?
        命令式语言告诉计算机以特定顺序执行某些操作。而对于声明式查询语言(如SQL或关系代数),则只需指定所需的数据模式,结果需满足什么条件,以及如何转换数据(例如,排序、分类和聚合),而不需指明如何实现这一目标。数据库系统的查询优化器会决定采用哪些索引和联结,以及用何种顺序来执行查询的各个语句。
        声明式查询语言很有吸引力,它比命令式API更加简洁和容易使用。但更重要的是,它对外隐藏了数据库引擎的很多实现细节,这样数据库系统能够在不改变查询语句的情况下提高性能。
        最后,声明式语言通常适合并行执行。现在CPU主要通过增加核,而不是通过比之前更高的时钟频率来提升速度。而命令式代码由于指定了特定的执行顺序,很难在多核和多台机器上并行化。声明式语言则对于并行执行更为友好,它们仅指定了结果所满足的模式,而不指定如何得到结果的具体算法。所以如果可以的话,数据库都倾向于采用并行方式实现查询语言。

2.1 Web上的声明式查询

        声明式查询语言的有点不仅限于数据库。CSS的选择器与JS的对象模型形成鲜明的对比。对于Web浏览器的例子,适用声明式CSS样式表比用Javascript命令式地操作样式好得多。类似地,在数据库中,像SQL这样的声明式查询语言比命令式查询APIs要好得多(例如性能提升和颜色擦除等方面)。

2.2 MapReduce查询

        MapReduce是一种编程模型,用于在许多机器上批量处理海量数据,兴起于Google。一些NoSQL存储系统(例如MongoDB和CouchDB)支持有限的MapReduce方式在大量文档上执行只读查询。
        MapReduce既不是声明式查询语言,也不是一个完全命令式的查询API,而是介于两者之间:查询的逻辑用代码片段来表示,这些代码片段可以被处理框架重复地调用。它主要基于许多函数式编程语言中的map(也称为collect)和reduce(也称为fold或inject)函数。
        MapReduce是一个相当底层的编程模型,用于在计算集群上分布执行。而SQL这样的更高层次的查询语言可以通过一些MapReduce操作pipeline来实现,当然也有很多SQL的分布式实现并不借助MapReduce。请注意,SQL并没有任何限制规定它只能在单个机器上运行,而MapReduce也并非垄断了分布式查询。

3 图状数据模型

        一开始,我以为图的顶点只能表示相同类型的事物。然而,图并不局限于这样的同构数据,图更为强大的用途在于,提供了单个数据存储区中保存完全不同类型对象的一致性方式。
        有多种不同但相关的方法可以构建和查询图中的数据。接下来将讨论属性图模型和三元存储模型,以及介绍三种声明式图查询语言,还有命令式图查询语言,以及图处理框架。

3.1 图属性

        图有利于演化:向应用程序添加功能时,图可以容易地扩展以适应数据结构的不断变化。
        可以将图存储看作由两个关系表组成,一个用于顶点,另一个用于边。为每个边存储头部和尾部顶点,如果想要顶点的入边或出边的集合,可以分别通过head_vertex或tail_vertex来查询edges表。

3.2 Cypher查询语言

        Cypher是一种用于属性图的声明式查询语言,最早为Neo4j图形数据库而创建。
        对于一个具体的需求,往往存在多种实现方式。对于声明式查询语言,通常在编写查询语句时,不需要指定执行细节:查询优化器会自动选择效率最高的执行策略,因此开发者可以专注于应用的其他部分。

3.3 SQL中的图查询

        可以采用关系数据库表示图数据。如果把图数据放在关系结构中,是否意味着也可以支持SQL查询呢?
        答案是肯定的,但存在一些困难。在关系数据库中,通常会预先知道查询中需要哪些join操作。而对于图查询,在找到要查找的定点之前,可能需要遍历数量未知的边,也就是说,join操作数量并不是预先确定的。
        Cypher可以用:WITHIN*O…非常简洁地表达语义:它表示“沿着一个WITHIN边,遍历零次或多次”,就像正则表达式中的*运算符(表示匹配零次或多次)那样。SQL:1999标准以后,查询过程中这种可变的遍历路径可以使用称为递归公用表表达式(即WITH RECURSIVE语法)来表示。但与Cypher相比,语法仍显得非常笨拙。
        如果相同的查询可以用一种查询语言写4行代码完成,而另一种查询语言则需要29行代码,这足以说明不同的数据模型适用于不同的场景。因此,选择适合应用程序的数据模型非常重要。

3.4 三元存储与SPARQL

        三元存储模式几乎等同于属性图模型,只是使用不同的名词描述了相同的思想。尽管如此,考虑到有多种针对三元存储的工具和语言,它们可能是构建应用程序宝贵的补充。
        三元组的主体相当于图中的顶点。而客体则是以下两种之一:

  1. 原始数据类型中的值,如字符串或数字。 在这种情况下,三元组的谓语和客体分别相当于主体(顶点)属性中的键和值。例如,(lucy,age,33)就好比是顶点lucy,具有属性{“age”,33}。
  2. 图中的另一个顶点。 此时,谓语是图中的边,主体是尾部顶点,而客体是头部顶点。例如,在(lucy,marriedTo,alain)中,主题lucy和客体alain都是顶点,并且谓语marriedTo是连接两者的边的标签。

3.4.1 语义网

        如果关于三元存储的信息,很可能会被卷入关于语义网大量文章漩涡之中。三元存储数据模型其实完全独立于语义网,例如,Datomic是一个三元存储,它与语义网并没有任何关系。
        语义网从本质上讲源于一个简单而合理的想法:网站通常将信息以文字和图片方式发布给人类阅读,那为什么不把信息发布为机器可以阅读的格式给计算机阅读呢? 资源描述框架(Resource Description Framework,RDF就是这样一种机制),它让不同网站以一致的格式发布数据,这样来自不同网站的数据自动合并成一个数据网络,一种互联网级别包含所有数据的数据库。

3.4.2 RDF数据模型

        使用的Turtle语言代表了RDF数据的人类可读格式。因为旨在为全网数据交换而设计,RDF存在一些特殊的约定。三元组的主体、谓语和客体通常是URI。例如谓语可能是URI,这种设计背后的原因是,它假设你的数据需要和其他人的数据相结合,万一不同人给单词within或者lives_in附加了不同的含义,采用URI则可以避免冲突。从RDF的角度来看,其不一定需要解析出特定的内容,它更多的只是一个命名空间。

3.4.3 SPARQL查询语言

        SPARQL是一种采用RDF数据模型的三元存储查询语言,它比Cypher更早,并且由于Cypher的模式匹配是借用的SPARQL的,所以二者看起来非常相似。执行同样的查询,SPARQL比Cypher更加简洁。

3.5 Datalog基础

        Datalog是比SPARQL或Cypher更为古老的语言,在20世纪80年代被学者广泛研究。虽然在软件工程师中知名度较低,但它为以后的查询语言奠定了基础,因此它非常重要。实践中有几个数据库系统采用了Datalog。例如它是Datomic系统的查询语言,而Cascalog是用于查询Hadoop大数据集的Datalog实现。
        Datalog的数据类型类似于三元存储模式,但更为通用一些。它采用“谓词(主体,客体)”的表达方式而不是三元组(主体,谓语,客体)。Cypher和SPARQL通过类似SELECT一次完成查询,而Datalog则每次实现一块。我们定义了告诉数据库关于新谓语的规则,例如两个新的谓语within_recursive和migrated。这些谓语并不是存储在数据库中的三元组,而是从数据或其他规则派生而来。规则可以引用其他规则,就像函数可以调用其他函数或者递归调用自己一样。像这样,复杂的查询可以通过每次完成一小块而逐步构建。
        Datalog方法需要采取与其他查询语言略有不同的思维方式,但它非常强大,特别是规则可以在不同的查询中组合和重用。对于简单的一次性查询来说,这或许不太方便,但是如果数据非常复杂,处理起来会更加游刃有余。

小结

        历史上,数据最初被表示为一棵大树(层次模型),但是这不利于表示多对多关系,所以发明了关系模型来解决这个问题。最近,开发人员发现一些应用程序也不太适合关系模型。新的非关系“NoSQL”数据存储在两个主要方向上存在分歧:

  1. 文档数据库的目标用例是数据来自于自包含文档,且一个文档与其他文档之间的关联很少
  2. 图数据库则针对相反的场景,目标用例是所有数据都可能会相互关联

        所有这三种模型(文档模型、关系模型和图模型),如今都有广泛的使用,并且在各自的目标领域都足够优秀。我们观察到,一个模型可以用另一个模型来模拟。例如,图数据可以在关系数据库中表示,虽然处理起来比较笨拙。这就是为什么不同的系统用于不同的目的,而不是一个万能的解决方案。
        文档数据库和图数据库都一个共同点,那就是它们通常不会对存储的数据强加某个模式,这可以使应用程序更容易适应不断变化的需求。但是,应用程序很可能仍然假定数据具有一定的结构,只不过是模式是显示(写时强制)还是隐式(读时处理)的问题。


推荐阅读
  • SparkOnYarn在YARN上启动Spark应用有两种模式。在cluster模式下,Spark驱动器(driver)在YARNApp ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
  • MySQL笔记_MySQL笔记1|数据库17问17答
    本文由编程笔记#小编为大家整理,主要介绍了MySQL笔记1|数据库17问17答相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Java工程师书单(初级,中级,高级)
    简介怎样学习才能从一名Java初级程序员成长为一名合格的架构师,或者说一名合格的架构师应该有怎样的技术知识体系,这是不仅一个刚刚踏入职场的初级程序员也是工作一两年之后开始迷茫的程序 ... [详细]
  • 《Spark核心技术与高级应用》——1.2节Spark的重要扩展
    本节书摘来自华章社区《Spark核心技术与高级应用》一书中的第1章,第1.2节Spark的重要扩展,作者于俊向海代其锋马海平,更多章节内容可以访问云栖社区“华章社区”公众号查看1. ... [详细]
  • Kylin 单节点安装
    软件环境Hadoop:2.7,3.1(sincev2.5)Hive:0.13-1.2.1HBase:1.1,2.0(sincev2.5)Spark(optional)2.3.0K ... [详细]
  • HBase系列之hbase2.2.3安装
    1.下载地址hbase-2.2.3下载地址2.解压安装1)解压tarzxvfhbase-2.2.3-bin.tar.gz2)环境变量配置vim ... [详细]
author-avatar
空灵一_一_379
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有