高效使用Greenplum:入门、进阶与数据中台
上QQ阅读APP看书,第一时间看更新

1.1 关系型数据库

说到大数据平台,我们必须从数据库的发展历史说起。数据库管理系统诞生于20世纪60年代,早期是各种数据模型“野蛮生长”,到20世纪90年代变成关系型数据库一统天下。SQL语言也伴随着关系型数据库的推广,成为一种重要的开发语言。

1.1.1 数据库发展历程

“数据库”一词诞生于1964年前后,由美国军事情报系统的工作人员提出,表示分时共享计算机系统中的多用户共享数据集合。现在维基百科对数据库的定义是按照一定方式组织起来的数据集合,通常使用数据库管理系统访问这些数据。

数据库管理系统的发展经历了很多阶段,早期很多数据库管理系统都消失在历史进程中,有些仍在不断迭代演进。

由于早期的数据模型衍生自打孔卡技术,因此比较简单,通常是由文件组成的。一个文件代表一个类型的数据,文件中的行代表一条记录,行由固定长度的列组成。随后衍生出层次模型的数据,层次模型主要用来表示实体之间的关联问题。基于层次模型的数据库由连接在一起的记录集合组成,一个记录包含多个字段,每个字段只有一个数据值,通过链接(Link)将两个记录关联在一起。层次模型适合表示一对一关系和一对多关系,无法表示多对多关系。IBM的IMS数据库就是一种层次模型数据库,也是最古老的数据库系统之一,至今仍然被一些企业使用。

为了解决多对多的关系,20世纪60年代末出现了网状模型。网状模型是由不同类型的记录集合组成的,记录之间的关系通过链接表示,如图1-1所示。20世纪70年代初,CODASYL的数据库工作组基于网状模型的商业数据库对网状数据模型进行了标准化,这种结构沿用至今。

000

图1-1 网状模型示例

20世纪60年代后期,Edgar F. Codd提出用集合论来表示实体集,其中实体集为域的集合,每一个域对应实体集中的一个属性。实体关联也用类似的方法表示,域对应实体的标识符。这个想法奠定了关系模型的理论基础。关系模型和层次模型、网状模型的最大区别在于,记录之间的关联关系不再使用指针表示,而是通过记录ID表示。还有一个区别是,层次模型、网状模型处理的基本单元是记录,而关系模型处理的基本单元是记录集合。从此,关系模型成为数据库领域的行业标准。

在关系模型之后,虽然业界也提出了对象数据模型和关系对象模型的概念,但是始终未能超越关系模型。其中PostgreSQL就是对象关系数据库的典型代表,只是最新版本中已经淡化了对象关系模型,仅保留了抽象数据类型、自定义数据类型、自定义操作符和函数等对象关系模型的一些功能。这也为PostgreSQL的灵活性和可扩展性奠定了坚实的基础。

在笔者大学期间,学校曾有一次公开课,邀请了武汉达梦数据库的总经理做了一次面向对象数据库的分享。面向对象数据库曾被视为国产数据库弯道超车的机会,然而这并没有变成现实。

回顾近十年来数据库的发展历程,真正实现数据库弯道超车的革新技术并不是数据模型的变化,而是列式存储的引入。

1.1.2 关系型数据库独霸天下

数据独立性是早期数据库系统追求的一个主要目标,指的是应用程序代码和数据存储结构、访问策略相互独立。用户可以通过数据库提供的高级接口处理数据,不用考虑底层细节,例如二进制位、指针、数组、链表等。

Edgar F. Codd提出的关系数据模型大大促进了数据独立性的发展。他认为传统数据库主要存储两种信息:数据库记录的内容和数据库之间的关系。不同的系统使用不同的方式存储记录之间的关系。

关系模型系统有3个重要的属性:提供一个和底层实现无关的数据模型或视图,所有信息都可以以数据值的方式表示,不存储任何连接信息;系统提供高级语言执行数据处理操作,而不用关心其他实现细节;高级语言以记录集合为操作单位,一次处理多个记录,层次数据库和网状数据库一次操作一个记录。基于这3个属性,关系数据模型可以更好地解决数据独立性问题。

正是凭借以上优势,关系模型数据库得以快速发展,并且称霸市场将近半个世纪。

1.1.3 结构化查询语言SQL

SQL语言也是助力关系模型数据库强势发展的伟大发明。SQL衍生自System R的数据库子语言,这是对数据库发展极为重要的一种高级语言。

SQL来自早期IBM对关系语言的研究。1972年,在Edgar F. Codd组织的一个计算机研讨会上,SQL的发明者Raymond Boyce和Donald Chamberlin接触到了关系数据模型。他们发现,用几行关系语言代码就可以实现复杂的DBTG语言程序才能实现的功能,于是被Codd关系语言的表达能力所震撼。不过,他们也感到该语言的门槛很高,需要具备一定的数学基础才能驾驭。于是1973年,他们设计了一种类似自然语言的查询语句—SEQUEL。该语言可以流畅地描述需要查询的信息,且不涉及任何实现细节,是一种声明式语言。1974年,他们发表了论文“SEQUEL:A Structured English Query Language”。之后,SEQUEL语言随着System R项目持续演进,根据早期用户的反馈,于1967年发布了更完整的SEQUEL语言设计。1977年由于商标问题,SEQUEL改为SQL。

举个例子,解决“比部门管理者薪水高的员工”这个问题的SQL查询如下,可以看到,查询语句非常简洁易懂。

select a.emp_code,a.emp_name
From employee a,employee b
Where a.manger_code = b.emp_code and a.salary >b.salary;

SQL的成功主要得益于关系模型的突破性创新,很好地抽象了用户和存储的数据库之间的交互,同时也推动了关系模型发展壮大。SQL同时支持DDL和DML,为用户提供了一个统一的接口来使用和管理数据库,从而提高了应用开发人员的工作效率。

1986年,ASNI和ISO标准工作组定义了SQL的标准。从此,SQL变成了一个完整的生态,不再被单个厂商锁定。此后,SQL发布了多个后续标准版本,包括1992、1996、1999、2003、2006、2008、2016。经过多年的发展,SQL标准逐渐修订了最初版本的不足,并增加了很多新的特性,包括外连接、表达式、递归、触发器、自定义类型和自定义函数、OLAP扩展、JSON等。

不过数据库市场被新兴的Oracle占了大头,导致SQL的后续版本变成指导方案,未能落地到产品中。Oracle的PLSQL随着Oracle数据库市场份额的膨胀,成为市场上功能最成熟的一个分支。

1.1.4 列存储的兴起

列存储(Column-based)是相对于行存储(Row-based)来说的。传统的数据库设计都是基于行存储,如Oracle、DB2、MySQL、SQL Server等,在基于行存储的数据库中,数据是以行数据为基础逻辑存储单元存储的,同一行的数据在存储介质中以连续存储的形式存在。

在实际应用中我们会发现,行式数据库在读取数据时存在一个固有的缺陷,比如,选择查询的目标虽然只涉及少数几个字段,但这些目标数据埋藏在各行数据单元中,而行单元往往又特别大,应用程序必须读取每一条完整的行记录,这使得读取效率大大降低。对此,行式数据库给出的优化方案是增加索引,在OLTP类型的应用中,通过索引机制或给表分区等手段简化查询操作步骤,提升查询效率。

针对海量数据背景的OLAP应用(例如分布式数据库、数据仓库等),行存储的数据库就有些力不从心了,因为行式数据库建立索引和物化视图需要花费大量时间和资源,所以还是不划算的,无法从根本上解决查询性能和维护成本的问题,也不适用于数据仓库等应用场景,因此后来出现了基于列存储的数据库。

对于数据仓库和分布式数据库来说,大部分情况下会先从各个数据源汇总数据,然后进行分析和反馈,大多数操作是围绕同一个字段(属性)进行的,而当查询某属性的数据记录时,列式数据库只需返回与列属性相关的值。在大数据量查询场景中,列式数据库可在内存中高效组装各列的值,最终形成关系记录集,可以显著减少I/O消耗并降低查询响应时间,非常适合数据仓库和分布式应用。

新兴的HBase、HP Vertica、SAP HANA、Pivotal Greenplum[1]、TiDB等分布式数据库均支持列存储。其中SAP HANA、Pivotal Greenplum、TiDB是同时支持行存储和列存储的数据库。在基于列存储的数据库中,数据是以列为基础逻辑存储单元存储的,同一列的数据在存储介质中以连续存储形式存在。行存储和列存储的差异如图1-2所示。

000

图1-2 行存储和列存储对比示例

行存储和列存储各有各的优点,有不同的应用场景。因为列存储是新兴的数据库存储方式,所以支持的数据库还不是很多,行存储的适用场景如下。

1)需要随机地增、删、改、查操作。

2)需要在行中选取所有属性的查询操作。

3)需要频繁插入或更新的操作,其操作与索引和行的大小更为相关。

列存储的适用场景如下。

1)查询过程中,可针对各列的运算并发执行,在内存中聚合完整的记录集,降低查询响应时间。

2)在数据中高效查找数据,无须维护索引(任何列都能作为索引),查询过程中能够尽量减少无关I/O,避免全表扫描。

3)因为各列独立存储,且数据类型已知,所以可以针对该列的数据类型、数据量大小等因素动态选择压缩算法,以提高物理存储利用率。如果某一列没有数据,在列存储时,就可以不存储该列的值,这比行存储更节省空间。


[1] 2019年底,Pivotal公司被Vmware收购。