本章主要讲了数据模型,以及围绕模型所构建的查询语言。

数据模型

关系模型

由Edgar Codd与1977年提出,这种模型将数据组织成关系(relations),在SQL中称为表(table),其中每个关系都是元组(tuples)的无序集合,也就是SQL中的行。

MySQL、Oracle、PostgreSQL等一众大家耳熟能详的数据库都属于此类。适用于:

  • 结构一致的数据。
  • 事务性要求比较高的情况,比如金融、银行等领域。

文档模型

所谓文档模型就是可以直接存储json、xml等非结构化数据,数据的关系和模式不再是首要关注的对象。相关的产品有Redis、MongoDB、HBase等等。

NoSQL[1]:不仅仅是SQL

最初作为一个标签出现在2009年的开源、分布式以及非关系数据库的见面会上。

NoSQL的优势:

  • 扩展性更好,支持超大数据集或超高吞吐量。
  • 大部分是免费开源,成本优势。
  • 查询的局部性更好,也就是一次将所有数据都查出来了,不用做联结和子查询。
  • 更具动态和表达力的数据模型,和应用程序数据结构比较接近,减少了阻抗失谐[2]

树模型

一个示例,下面是比尔盖茨个人简历的json描述:

{
    "user id": 251,
    "first_name": "Bill",
    "last_ name": "Gates",
    "summary": "Co-chair of the Bill & Melinda Gates... Active blogger.",
    "region id": "us:91",
    "industry_id": 131,
    "photo ur1": "/p/7/000/253/05b/308dd6e.jpg",
    "positions": [
        {"job_title": "Co-chair", "organization": "Bill & Melinda Gates Foundation"},
    	{"job_title": "Co-founder, Chairman", "organization": "Microsoft"}
    ],
    "education": [
        { "school_name": "Harvard University", "start": 1973, "end": 1975 },
    	{ "school_name": "Lakeside School, Seattle", "start": null, "end": null }
    ],
    "contact info": {
    	"blog": "http://thegatesnotes.com",
    	"twitter": "http://twitter.com/BillGates"
    }
}

画成图是这个样子。

tree model

可以看到是一层一层的,像一棵树,所以有时候也称为层次模型或树模型。

其实json并非没有模式,只是和关系模型相比,一个是写式模式(显式),一个读时模式(隐式),json格式更易修改,不用像关系数据库得修改表结构。

json拥有更好的局部性,不用联接(join)多张表或者多次查询,但仅限于访问大部分数据情况,无法像关系数据库返回特定字段。

json擅长处理1 vs N,不擅长处理N vs 1和N vs N。想支持只能在应用层使用代码做,另外是不是还增加了数据冗余度,因为不能像关系数据库那样通过外键引用同一份数据。

网络模型

不像层次模型,每个记录只有一个父节点,网络模型可以有多个父节点,比如“大西雅图地区”可能是一个记录,居住在该地区的用户都指向它,因此可以方便的支持多对一和多对多。

比如这个多对多的例子。

net model

融合数据库

关系数据库和文档数据库呈现出融合趋势,主流的关系数据库PostgreSQL、MySQL、DB2已经支持json、xml等常用文档类型。文档数据库RethinkDB查询接口支持和关系型类似的联结,MongoDB驱动程序可以自动解析数据库的引用关系。

图状数据模型

关系模型可以勉为其难的处理多对多,但是还是图模型更自然。

图有两种对象构成:顶点和边,典型的例子:

  • 社交网络:顶点是人,边指示哪些人彼此认识。
  • Web图:顶点是网页,边表示网页之间的超链接。
  • 公路或铁路网:顶点是交叉口,边表示它们之间的公路线或铁路线。

一个示例,来自社交网络的族谱数据库,来自爱达荷州的Lucy和来自法国波恩的Alain,他们结婚了,目前住在伦敦。

graph model

图模型最大的特点就是灵活,它的灵活性来自于:

  • 任何顶点之间都可以连接。
  • 给定某个顶点,可以高效的得到它的入边和出边,从而遍历图。
  • 可以在同一张图的同一顶点之间标记不同的标签来表达不同的关系,同时仍然保持图的整洁。

图数据模型可以使用关系数据库和三元存储实现。

关系数据表

如果是关系数据表实现,相应地可以用SQL查询,但是写起来比专门的图查询语言麻烦多了。

CREATE TABLE vertices (
    vertex_id   interger PRIMARY KEY,
    properties  json
);

CREATE TABLE edges (
    edge_id     integer PRIMARY KEY,
    tail_vertex integer REFERENCE vertices (vertex_id),
    head_vertex integer REFERENCE vertices (vertex_id),
    label       text,
    properties  json
);

CREATE INDEX edges_tails ON edges (tail_vertex);
CREATE INDEX edges_heads ON edges (head_vertex);

三元组

几乎等同于属性图模型,所有信息都表示为(主体,谓语,客体)。例如,(吉姆,喜欢,香蕉)。三元组的主体相当于图的顶点,客体可能是:

  • 属性值,比如(lucy,age,33)。
  • 顶点,比如(lucy,marriedTo,alain)。

以Turtle[3]三元组的形式表示图:

@prefix : <urn:example:>.
_:lucy      a :Person;          :name "Lucy";          :bornIn _:idaho.
_:idaho     a :Location;        :name "Idaho";         :type "state";   :within _:usa.
_:usa       a :Location;        :name "United States"; :type "country"; :within _:namerica.
 :namerica  a :Location;        :name "North America"; :type "continent".

RDF(Resource Description Framework)是一种基于xml的资源描述框架,目的是为不同的网站定义一种通用格式,这样不同的网站可以自动合并成一个数据网络,一种互联网级别包含一切数据的数据库。

我个人觉得Turtle是给人看的三元组,RDF是给机器看的三元组。

语义网

语义网源自大家想创建一种囊括互联网所有数据的大数据库的设想,为了创建这种数据库,需要所有人都遵守一种通用格式,就像人为了能够理解彼此,必须得说同样地语言,为了描述这种格式诞生了RDF。

在可预见的未来,大多数系统会同时使用关系数据库和NoSQL数据库,称为混合持久化

数据查询语言

命令式

需要告诉程序一步一步怎么做,大多数的编程语言都属于此类。

声明式

告诉程序做什么即可,具体怎么做程序自主决定,如SQL、web中的css和xsl。

SQL

比如使用SQL查询每个月看到了多少鲨鱼。

SELECT date_trunc('month', observation_timestamp) AS observation_month,
       sum(num_animals) as total_animals
FROM observations
WHERE family = 'Shark'
GROUP BY observation_month;

聚合管道

MongoDB 2.2增加了聚合管道的声明式查询语言,相当于SQL的子集,基于json语法。它的等效表达如下:

db.observations.aggregate(
    { $match: { family: "Shark" } },
    { $group: {
        _id: {
            year: { $year: "observationTimestamp" },
            month: { $month: "observationTimestamp" }
        },
        totalAnimal: { $sum: "$numAnimals" }
    }
);

感觉某种程度上,可以看成是文档数据库的SQL语言。

Cypher

Cypher查询语言,一种属性图的声明式查询语言,最早为Neo4j图形数据库而创建。比如,使用Cypher查询从美国移民到欧洲的人员名单:

MATCH
    (person) -[BORN_IN]-> () -[:WITHIN*O..]-> (us:Location {name:'United States'}).
    (person) -[LIVES_IN]-> () -[:WITHIN*O..]-> (eu:Location {name:'Europe'}).

SPARQL

SPARQL(发音:sparkle),是一种基于RDF的查询语言。比如,执行同样的查询,比Cypher
更加简洁[4]

SELECT ?personName WHERE {
    ?person :name ?personName.
    ?person :bornIn / :within* / :name "United States".
    ?person :liveIn / :within* / :name "Europe".
}

  1. 又仔细看了下书,NoSQL是相对SQL(关系模型)而说的,应该不仅包括文档模型,还包含之后的图模型。 ↩︎

  2. 编程语言中是一些对象,而关系数据库基本单元是行和列,模型之间的这种脱离称为阻抗失谐。 ↩︎

  3. Turtle是Notation3的子集。 ↩︎

  4. 简不简洁见仁见智,但是看起来更像SQL倒是真的。 ↩︎