Design Data-Intensive Applications 读书笔记三 查询语句

数据查询语句

引入关系模型的时候,它引入了一个新的查询数据的方法:SQL是一个声明式查询语言,IMS和CODASYL查询用的是命令式语言。

一些常用的编程语言都是命令式的。

在关系型语法汇总,你会这样写:

Design Data-Intensive Applications 读书笔记三 查询语句

命令式语言告诉电脑按顺序执行操作。你可以想象电脑按行遍历代码,计算条件,更新变量,决定是否继续循环。

在声明式语言中,你只需要设定你想要的数据:什么条件能拿到结果,数据怎么传输(sored,grouped,aggregated),而不是如何达成这些目标。这些都取决于数据库系统的查询优化器来决定使用哪些索引,哪些连接操作,以及查询语句不同部分的执行顺序。

声明式语言很有吸引力,因为它比命令式语言更加清晰,更容易。更重要的是,它隐藏了数据库引擎的实现细节,这使得数据库性能的提升与查询语句隔离了。

声明式查询

声明式查询语句的优势不限于数据库。让我们比较命令式和声明式方法在浏览器中的应用。

假设你有一个关于海洋动物的网站。用户在浏览“鲨鱼”这一页,所以你将导航菜单中的“鲨鱼”标注选中,例如

Design Data-Intensive Applications 读书笔记三 查询语句

选中标签标注为CSS类“selected”。当前选中页面为Shark。

现在你想要当前选中页面为蓝色背景,用CSS语言:

Design Data-Intensive Applications 读书笔记三 查询语句

 

CSS选择器li.selectd>p 声明了我们想要变为蓝色风格的元素的模式:即那些直接父节点是一个<li>元素的所有<p>元素,并且CSS样式为selected。元素<p>sharks</p>在这个例子中符合这个模式,<p>Whale<p>不符合,因为父节点<li>缺少属性class=“selected”。

如果你使用XSL代替CSS,同样的功能:

Design Data-Intensive Applications 读书笔记三 查询语句

XPath表达式 li[@class='selected']/p 等同于CSS选择器  li.selected > p 。CSS和XSL相同之处就是他们都是用于特定风格文档的声明式语言。

设想一下使用命令式语言要怎样做。在JavaScript中使用文档对象模型DOM API,结果可能是:

Design Data-Intensive Applications 读书笔记三 查询语句

JavaScript设置元素<p>Sharks</p> 为蓝色背景,但是代码很难看。不仅比XSL和CSS难以理解,而且还有其他问题:

1、如果 selected 属性移除了(用户点击其他页面),蓝色也不会移除,即便是重新执行代码,所以元素会持续高亮显示直到整个页面重新加载。使用CSS,只要selected属性移除,浏览器能够自动检测到 li.selected > p 不再适用,移除蓝色背景。

2、如果你想使用新API,例如可能提高性能的 document.getElementsByClassName("selected") 或者  document.evaluate(),你必须重写代码。另一方面,浏览器渲染器可以不破坏兼容性而提高性能。

在Web浏览器中,使用声明式的CSS样式比JavaScript中的命令式操作要好。类似的,数据库中声明式的查询语句不命令式的查询API要好用。

MapReduce查询

MapReduce是用于在多台机器间批量处理海量数据的编程模型,由Google推广。由NoSQL数据库支持的有限格式,用于在多个文档中用于只读的查询。这章我们只讨论MongoDB对这个模型的使用。

MapReduce既不是声明式查询语句也不是命令式查询语句,而是介于两者中间:使用代码片段来表示查询逻辑,同时运行框架会不停的调用。它基于 map(也叫 collect) 和 reduce(也叫fold或者inject)这些存在于很多函数式编程语言中的函数。

在PostgreSQL中你可能如下表达查询

Design Data-Intensive Applications 读书笔记三 查询语句

 

date_trunc('month', timestamp) 函数输入包含月份的时间戳,然后返回表示月份开始的时间戳,换句话说,它将一个时间戳降至最近的月份。

查询语句首先过滤出Shark 那一类,然后按照它们出现的月份整合分组,然后按照月份求和。

MongoDB中同样功能的MapReduce表达式如下:

Design Data-Intensive Applications 读书笔记三 查询语句

标签1:表示只考虑 Sharks 这一类

标签2:map函数会对每个查询到的文档调用一次,this 关键字指定文档对象。

标签3:map函数提交了一个键(由年和月份组成)和一个值(观测到的动物的数量)

标签4:map函数提交的键值对会根据键值来分组,对于每个有相同键值的键值对集合会调用一次

标签5:reduce 函数将所有特定月份的动物观测数据加起来

标签6:最后结果写入到集合 monthlySharkReport

map 和 reduce 被限制了他们只能做什么,是纯粹的函数,意味着它们只能使用传入进去的数据,而且不能进行额外的数据库查询操作,而且不能有任何副作用。这些限制允许数据库任何时候以任何顺序运行函数,失败的时候重新执行。尽管有着诸多限制,他们依然是强大的。

对于集群来说,mapreduce是一个低等级的编程模型。高等级的编程模型比如SQL可以实现成MapReduce的操作流,但是目前很多SQL的分布式实现不使用MapReduce。注意SQL中没有限制它只能运行在一台机器上。而且MapReduce并没有在分布式查询操作上取得垄断。

对于高级查询来说能够在查询中使用JavaScript代码是个很好的特性。但是它不局限于MapReduce,一些SQL数据库能够使用JavaScript函数来扩展。

MapReduce在使用中有个问题,你不得不很小心地实现两个规定好的JavaScript函数,这比单纯写一个查询要难。而且,声明式查询语句能够给查询优化器提供更多提高性能的机会。因为这些原因,MongoDB2.2 增加了声明式查询语言:聚合管道aggregation pipeline。用这个语言写鲨鱼计数查询可能是:

Design Data-Intensive Applications 读书笔记三 查询语句

aggregation pipeline在表达上类似于SQL的一个子集,但是它是使用基于JSON的语法而不是SQL的英语语法,这个差异可能造成理解困难。所以这个讨论的核心就是NoSQL系统可能碰巧再发明了SQL语句,尽管只是形式上的。