购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3.1 数据库查询语言的基础概念

我们正处于一个大数据的时代,互联网和移动互联网络的快速发展带来了数据产生速率的极大增长。每天每时每刻都有数以十亿量级的设备(有人预计在2030年前,会有超过千亿量级的联网传感设备)在产生巨大体量的数据。数据库是被人们创造出来解决这种不断增长的数据利器。还有其他类似的概念、工具和解决方案,如数据仓库、数据集市、数据湖泊等,来解决我们日常所面对的数据存储、数据转换、数据分析、汇总、报表等一系列工作,当然,比起数据库而言,后面这些相对新型的“赛道”的规模远不足以匹敌数据库赛道(数据库是接近千亿美元的单一赛道,以业界龙头Oracle为例,其一年的收入达到400亿美元)。是什么让数据库变得如此重要,以至于我们对其难以割舍呢?笔者认为,有两件事情是数据库的核心“竞争力”:性能和查询语言。

在现代商业社会中,性能从来都是“一等公民”。一个数据库之所以被称作数据库,意味着它可以在合理的,通常是最小的,至少是符合商业诉求的延迟内来完成规定的工作。在这一点上,数据库和商务智能时代的很多数据仓库或Hadoop大数据阵营的解决方案显得很不相同,后者或许有着很好的分布式、可扩展,甚至是在低配置的“烂机器”上可以运行的能力,但是它们的性能绝不是“令人骄傲”的优势之一。这或许可以解释为什么我们在近年看到了市场上关于Hadoop已经过时的一些看法,以及很多商业落地场景中,基于内存计算的Spark和其他一些新型的基础架构正在不断取代Hadoop。

从大数据向快数据(fast data)转型或迁移是为了让底层的数据库框架可以应对不断增长的数据规模,而不至于牺牲数据处理性能(数据吞吐率)。图2-31展示了以数据库为中心的数据处理基础架构和技术的进化路径:从数据到大数据,从大数据到快数据,再从快数据到深数据。

图2-31 从数据到大数据、快数据再到深数据的进化路线

数据库查询语言(database query language)是计算机编程语言出现以来被发明出来的最好的事物之一。我们希望计算机程序可以有着人类一样对数据智能化、深度筛选、动态组装信息的能力,但是这种强人工智能的诉求目前为止还没有被真正实现。退而求其次,聪明的程序员们、语言学家们通过计算机编程语言将人类的意图、指令实现,而数据库中的查询语言就是这种可以面向数据的“半智能化”的数据处理语言。

在进入众所周知的SQL世界之前,先来了解一下非关系型数据库(如NoSQL等)所支持的查询语言的一些特性。

首先,我们来看一下键值数据库,常见键值库的实现有BerkeleyDB、LevelDB等。在技术上,键值库并不支持或使用确切的查询语言,这是因为它所支持的操作实在是太简单了,使用简单的API就已经足够了。典型的键值库支持3种操作:插入(insert)、读取(get)和删除(delete)。

有的读者可能会说Cassandra支持CQL(Cassandra Query Language)。没有问题,Cassandra实际上是一种宽列库,我们可以把它看作是一种二维的键值库。对于Cassandra所支持的数据操作复杂度极高且高度分布式的架构而言,提供一层抽象查询语言来减少程序员的工作负担是绝对有其正面意义的,否则程序员就需要记住那些复杂的API调用函数的各种参数集合。另外,CQL使用了与常规SQL类似的概念,如表、行、列等。我们后续会更多讨论SQL相关的内容。

对Apache Cassandra(或许可以看作是对NoSQL数据库的整体而言的)的一个批评是CQL并不支持SQL中常见的join(表连接)操作。很显然,这种批评的思路是深深地根植于SQL的思维方式中的。join操作是把双刃剑,它在解决一件事情的同时也带来了一个问题,比如(巨大的)性能损耗。事实上,Cassandra可以支持join操作,有以下两种解决方案(图2-32)。

·Spark SQL:Cassandra实现的一种SQL方言;

·ODBC驱动:Cassandra提供的ODBC驱动。

图2-32 在Spark结构化数据架构上的Spark SQL查询语言

然而,这些解决方案是有代价的,例如ODBC在面向大数据集或集群化操作时需要解决性能问题。而Spark SQL则是在Cassandra基础上又叠加一层新的系统复杂度,对于多系统维护、系统稳定性,以及不少程序员苦于了解新系统、学习新知识而言,都是挑战。

关于Apache Spark和Spark SQL不得不多说两句,Spark设计之初就是要应对Apache Hadoop的低效性和低性能。Hadoop从谷歌的GFS(谷歌文件系统)和Map-Reduce理念及实现中借鉴了两个关键概念,并由此而创造了HDFS(Hadoop分布式文件系统)和Hadoop MapReduce;Spark则相当于利用分布式共享内存架构实现了100倍的相对于Hadoop而言的性能提升。打个比方,仅仅是简单把数据从硬盘移到内存中来处理,就会获得100倍左右的性能提升,因为内存的吞吐率是硬盘的100倍左右。Spark SQL提供了一个SQL兼容的查询语言接口来支持访问Spark中的结构化数据,相比于Spark原生的RDD API而言,Spark SQL已经是一种进步——如前所述,如果API过于复杂,那么对查询语言的诉求就变得越来越强烈了,因为它更加灵活、实用、强大。

笔者十几年前在Yahoo!战略数据部(SDS)就职期间,正是Yahoo!在孵化Hadoop项目的时期,相比SDS的其他高性能、分布式海量数据处理框架实现而言,Hadoop在性能上的表现差强人意。笔者印象最深刻的就是很多Linux中常见的排序、搜索等工具都被改写为可以以极高的性能来应对海量数据的处理,例如sort命令的性能被提升100倍以上来应对GB到TB量级的大数据集的排序挑战。或许这也能解释为什么Hadoop后来被Yahoo!捐献给了Apache开源社区,而其他显然更有优势的项目却没有被开源。或许读者应该思考:开源的就是最好的吗?

比照图2-31提及的整个业界的数据处理技术的演化(从数据→大数据→快数据→深数据),对应的底层数据处理技术就会从关系型数据库主导的时代向非关系型数据库(如NoSQL、Spark等)、NewSQL和图数据库框架的时代演进。依据这种趋势和演化路径可以大胆预判,未来的核心数据处理基础架构一定是至少包含或由图架构主导的。

过去半个世纪的数据库技术的进化可通过图2-33来概括:从20世纪70年代之前的导航型数据库,到20世纪70—80年代的关系型数据库,到90年代SQL编程语言的兴起,再到21世纪第一个10年后出现的各种NoSQL——或许图2-33留给我们一个迷思,图查询语言会是终极的查询语言吗?

换个角度问个问题:人类终极的数据库是什么?或许你不会反对这个答案:人脑!人类的大脑到底是什么样的数据库技术?笔者以为是图数据库,至少在概率上它远远高于关系型数据库、列数据库、键值库或任何文档数据库,又或许是我们还没有发明的一种数据库。但是图数据库是最接近终极数据库的,毋庸置疑。

图2-33 数据库和查询语言的进化历史

如果读者对于SQL语言的演进有所了解,知道它直接推动了关系型数据库的崛起(如果诸位还能回忆起在SQL语言出现之前的数据库使用是如何笨拙与痛苦的话)。互联网的崛起催生了NoSQL的诞生和崛起,其中很大的一个原因是关系型数据库无法很好地应对数据处理速度、数据建模灵活性的诉求。NoSQL数据库一般被分为以下4或5大类,每一类都有其各自的特性。

·键值(key-value):性能和简易性。

·宽列(wide-column):体量与性能。

·文档(document):数据多样性。

·图(graph):深数据与快数据。

·(可选的)时序(time series):IOT数据、时序优先性能。

从查询语言(或者API)的复杂度来看,数据处理能力也存在着一条进化路径。图2-34形象地表达了NoSQL类数据库和以SQL为中心的关系型数据库之间的区别。

·相对原始的键值库API→有序键值库(ordered key-value)。

·有序键值库→大表(一种典型的宽列库)。

·大表→文档数据库(例如MongoDB),并带有全文搜索能力(搜索引擎)。

·文档数据库→图数据库。

·图数据库→SQL中心化的关系型数据库。

图2-34 数据库查询语言的进化(一家之言)

如图2-34所示,SQL被认为是最先进的数据处理与查询语言。下面稍微深入地研究一下SQL的演化历史,让我们有个更全局化的概念。

SQL的出现已将近50年了,并且迭代了很多版本(平均3~4年一次大迭代),其中最知名的非SQL-92、SQL-99莫属,例如在92版本的FROM语句中增加了子查询(subquery)功能;在99年版本中增加了CTE(Common Table Expression)功能。这些功能极大地增加了关系型数据库的灵活性,如图2-35所示。

图2-35 SQL-92中的子查询与SQL-99中的CTE

然而,关系型数据库始终存在一个“弱点”,那就是不支持递归型数据结构。所谓递归数据结构(recursive data structures),指的是有向关系图的功能实现。讽刺的是,关系型数据库的名字虽然包含了关系,但是它在设计之初就很难支持关联关系的查询。为了实现关联查询,关系型数据库不得不依赖表连接操作——每一次表连接都意味着潜在的表扫描操作,随之而来的是性能指数级下降,以及SQL语句、代码复杂度的直线上升。

表连接操作的性能损耗是直接源自关系型数据库的基础设计思想的:

·数据正则化;

·固定化的、预先设定的表模式。

回顾一下NoSQL的核心理念,它在数据建模中突出了数据去正则化。所谓数据正则化,指的是用空间换取时间(牺牲空间来换取更高的性能)。在NoSQL(也包括Hadoop等,例如典型的3、5、7份拷贝的理念)中,数据经常被以多份拷贝的方式存储,而这样做的好处在于数据可以以近邻计算资源的方式被处理。这种理念和SQL中的只存一份正则化设计思路是截然相反的——后者或许可以节省一些存储空间,但是对于复杂的SQL操作而言,带来的是性能损耗。

预先定义数据的表模式理念是SQL与NoSQL的另一大差异。对于初次接触这一概念的读者而言,理解这个点会有些困难,它实际上指的是SQL中模式第一、数据第二,而在NoSQL中数据先行、模式第二。

在关系型数据库中,系统管理员(DBA)需要先定义表的结构(schema),然后才会加载第一行数据进入数据库,他不可能动态地更改表的结构。这种僵化性对于固定模式、一成不变的数据结构和业务需求而言或许不是什么大问题。但是,让我们想象一下,如果数据模式可以自我调整,并能根据流入的数据动态调整,这就给我们带来了极大的灵活性。对于强SQL背景的人而言,这是很难想象的。但是,我们需要暂时抛弃僵化的、限制性的思维,以一种成长性的思维方式来看待。我们所要达成的目标是一种schema-free或schemaless的数据模式,也就是无需预先设定数据模式,数据之间的关联性不需要预先定义和了解,随着数据的流入,它们会自然形成某种关联关系。而数据库所需要做的是对应这些数据“因地制宜”来处理如何查询与计算。

在过去几十年中,数据库程序员已经被训练得一定要先了解数据模型,不论它是关系型表结构还是实体E-R模式图。了解数据模型当然有它的优势,但这也让开发流程变得更加复杂和缓慢。程序员读者们,你还记得上一次参与的交钥匙解决方案的开发周期是多长时间吗?一个季度、半年、一年还是更久?在一个有8000张表的Oracle数据库中,没有任何一个DBA可以完全掌握所有表之间的关联关系。这个时候,我们更愿意把这套脆弱的系统比作一个定时炸弹,而你的所有业务都绑定在其上。

关于无模式(schema-free),在文档型数据库或宽列数据库中已经有了这一概念,尽管它们多少有一些和图数据库相似的设计理念。下面通过一些图数据库的具体例子来帮助读者理解无模式。 EIm1Xr7bq1to+kjZ+n6FajgDaIj+sSMoJGAeMpuft8qiR2rSRkM3By95VnlO8d5m

点击中间区域
呼出菜单
上一章
目录
下一章
×