数据库语言的目标
为了明确这个目标,我们需要先了解数据库是干什么的。

说到数据库,总是让人以为它主要是为了存储,因为它的名字中有“基”的部分。但实际上并非如此,数据库可以实现两个重要的功能:计算和事务,也就是 我们常说的OLAP和OLTP。数据库的存储就是为这两个功能而存在的,仅仅起到存储的作用并不是数据库的目的。

众所周知,SQL是目前主流的数据库语言。那么,用SQL做这两件事方便吗?

事务功能主要是解决数据写入和读取时的一致性问题。虽然实现起来比较困难,但是对于应用程序来说它的接口非常简单,而且操作数据库读写的代码也非常简单。如果假设目前关系型数据库的逻辑存储方案是合理的(即使用数据表和记录来存储数据,合理与否是另一个复杂的问题,这里不做详细讨论),那么用SQL来描述事务功能就不是什么大问题了,因为不需要描述复杂的action,复杂度已经在数据库中解决了。

但是,对于计算功能,情况会有所不同。

我们这里所说的计算是一个更广泛的概念。不仅仅是简单的加减法,查找和联想都可以看作是一些计算。

那么问题来了,什么样的计算系统好呢?

需要两个特性:易于编写和快速运行。

Easy in writing就是容易理解,就是让程序员可以快速的编写代码,从而在单位时间内完成更多的工作;而对于快速运行,更容易理解,因为我们当然希望在更短的时间内得到计算结果。

SQL中的Q其实就是query。发明SQL的初衷是为了查询(即计算),这是SQL的主要目标。但是,在描述计算任务时,很难说SQL很胜任。

SQL为什么不能胜任
让我们从简单的写作开始。

SQL写的代码很像英文,有些查询是可以用英文读写的(网上例子太多了,这里就不举例了)。这应该算是满足了易写的要求。

等一下!我们在教科书上看到的用SQL写的代码往往只有两三行,确实简单,但是如果我们要解决一些稍微复杂一点的问题呢?

下面举个例子,其实也不是很复杂:计算一只股票价格持续上涨的最大连续天数。写成SQL是这样的:

数据库
select max (consecutive_day)
from (select count(*) (consecutive_day
      from (select sum(rise_mark) over(order by trade_date) days_no_gain
            from (select trade_date,
                         case when closing_price>lag(closing_price) over(order by trade_date)
                              then 0 else 1 END rise_mark
                  from stock_price ) )
      group by days_no_gain)
这个语句的工作原理这里就不多说了,反正有点费解。你可以自己试试。

这是Raqsoft公司的招聘测试,通过率不到20%;因为太难了,后来改成另一种测试方式:要求考生说明写的SQL语句是什么,可惜通过率还是不高。

它揭示了什么?揭示出情况稍微复杂了,SQL变得既难看又难写!

我们来看快速跑分的问题,以经常使用的简单任务为例:从1亿条数据中取出前10条。这个任务用 SQL 写起来并不复杂:

数据库
SELECT TOP 10 x FROM T ORDER BY x DESC
但是这条语句对应的执行逻辑是先对所有数据进行大排序,然后取前10,其余数据丢弃。众所周知,排序是一个很慢的动作,会遍历数据很多次。如果数据量太大,无法加载到内存中,还需要将数据缓冲到外部存储中,导致性能进一步急剧下降。如果严格遵循这条语句中体现的逻辑,无论如何操作都不会跑得很快。幸运的是,很多程序员都知道这个操作不需要大排序,也不需要外部存储缓冲,只需要遍历一次,占用内存空间很小,这意味着有更高性能的算法存在。遗憾的是,这样的算法无法在SQL 中实现。

看来SQL在这两方面都做的不太好。虽然这两个例子都不是很复杂,但是 SQL 在这两个例子中的表现都不好。现实中,数千行的SQL代码中,难于编写、运行缓慢的情况比比皆是。

那么,为什么这两个方面在SQL中就不能很好的实现呢?

要回答这个问题,我们需要分析一下程序代码的计算具体实现是做什么的。

从本质上讲,编程的过程就是将解决问题的思想转化为计算机可执行的精确形式化语言的过程。例如小学生做一道应用题,在分析题想出答案后,也需要列出与四种基本算术运算有关的表达式。同样,用程序进行计算,不仅需要想出解法,还需要将解法转化为计算机可以理解和执行的动作。

对于描述计算方法的形式化语言,其核心在于所采用的代数系统。简单来说,所谓代数系统包括两个关键要素:数据类型和相应的运算规则。例如,我们在小学学习的算术核心是整数和加、减、乘、除运算。一旦我们得到了这两个关键要素,我们就可以用代数系统规定的符号将我们想要的运算写成某种东西,即代码,然后计算机就可以执行了。

如果一个代数系统设计不好,导致提供的数据类型和操作不方便,就会使算法描述变得非常困难。在这种情况下,会出现一个奇怪的现象:将解决方案转化为代码的难度远远超过解决问题本身。

例如,我们小时候学会了用阿拉伯数字进行日常计算,用这样的数字做加减乘除非常方便,所以大家自然而然地认为数字运算就应该是这样的。所有的数值运算都这么方便吗?不必要!估计很多人都知道还有一种数字叫罗马数字。你知道罗马数字的加减乘除吗?而古罗马人是如何上街购物的呢?

编码困难的原因很大程度上是由于代数。

再来看看跑不快的原因。

软件不能改变硬件的性能;CPU和硬盘的速度取决于各自的配置。但是我们可以设计一个复杂度低的算法,也就是计算量小的算法,这样计算机执行的动作就少,运行速度自然也就快了。然而,仅仅计算出算法是不够的,我们还需要用某种形式化的语言来编写算法,否则计算机将无法执行。此外,它需要相对简单的代码。如果某种形式语言的代码很长,会很麻烦,而且没有人会使用这种形式语言。因此,对于程序来说,编写简单, 运行速度快 其实都是同一个问题,背后是形式语言采用的代数。如果代数不好,就很难甚至无法实现高性能的算法,也就没有办法跑得快。上面说到我们想要的占用内存空间小,只遍历一次的算法在SQL中是无法实现的。因此,要想跑得快,只能寄希望于优化器。

我们再打个比方:

上过小学的同学应该都知道高斯计算1+2+3+…+100的故事。普通学生采用的是最原始的方法,就是一步步加100次,而小高斯却很聪明,他发现1+100=101,2+99=101,……,50+51=101,从中他用 50 乘以 101,很快算出了结果,然后就回家吃午饭了。

听完这个故事,我们都觉得高斯太聪明了,竟然想到了这么巧妙的解法,简单快捷。是的,没错,但是很容易忽略一点:在高斯时代,乘法 已经存在于人类的算术系统(也是一种代数)中!如前所述,由于我们小时候学过四种算术运算,因此我们理所当然地认为应该使用乘法。但事实并非如此!乘法是在加法之后发明的。如果在高斯那个时代乘法还没有被发明出来,就算高斯再聪明,他也不会很快找到解决这个问题的方法。

目前主流的数据库是关系型数据库,之所以这样称呼是因为它的数学基础叫关系代数。SQL正是从关系代数理论发展而来的一种形式化语言。

现在我们可以回答为什么 SQL 在我们期望的两个方面都不能胜任。问题出在关系代数上,关系代数就像一个只有加法没有乘法的算术系统。所以,很多事情做不好是难免的。

关系代数已经发明了五十年。五十年前的应用需求和硬件环境与今天的差别是非常巨大的。继续用五十年前的理论来解决今天的问题,听起来是不是太落伍了?然而,这就是现实。由于现有用户众多,缺乏成熟的新技术,基于关系代数的SQL仍然是当今最重要的数据库语言。虽然近几十年来有所改进,但基础没有改变。面对当代复杂的需求和硬件环境,SQL无能也在情理之中。

而且,不幸的是,这个问题是在理论层面的,在实践中再怎么优化也无济于事,只能有限地改善,不能根除。遗憾的是,大多数数据库开发人员并没有想到这个层次,或者说,为了照顾现有用户的兼容性,他们不打算考虑这个层次。于是,主流数据库行业一直在这个有限的空间里兜圈子。

SPL为何胜任
那么,如何让计算写起来更容易,运行起来更快呢?

发明新的代数! 一个带“乘法”的代数,然后在新代数的基础上设计一门新的语言。

这就是 SPL 的来源。它的理论基础不再是关系代数,而是一种叫做离散数据集的东西。基于这种新代数设计的形式化语言被命名为SPL  (Structured Process Language)。

针对SQL的缺点对SPL进行了创新(更确切地说,针对关系代数的各种不足对离散数据集进行了创新)。SPL重新定义和扩展了结构化数据的很多操作,具体来说,它增加了离散性,增强了有序计算,实现了彻底的面向集合,支持对象引用,提倡逐步操作。

在SPL中重新编码以前的问题会给你一个直接的感受。

计算股价持续上涨的最大连续天数:

stock_price.sort(trade_date).group@i(closing_price<closing_price[-1]).max(~.len())
虽然计算思路和之前的SQL一样,但是因为引入了排序特性,表达起来更容易,不再混乱。

从1亿条数据中取出前10条:

T.groups(;top(-10,x))
SPL具有更丰富的集合数据类型,很容易描述出一次遍历即可实现简单聚合的高效算法,无需涉及大的排序动作。

限于篇幅,这里不全面介绍SPL(discrete dataset),而是列举SPL(discrete dataset)相对于SQL(关系代数)的一些差异化改进:

离散记录
离散数据集中的记录是一种基本数据类型,可以独立于数据表而存在。数据表是由记录构成的集合,组成某个数据表的记录也可以用来组成其他数据表。例如,过滤操作就是将原数据表中满足条件的记录组成新的数据表,这样无论是在空间占用上还是在运行性能上都更有优势。

关系代数没有可计算的数据类型来表示记录。单条记录实际上就是一个只有一行的数据表,不同数据表中的记录不能相同。例如,在过滤操作过程中,新的记录会被复制,形成新的数据表,这会导致空间和时间成本的增加。

特别是,由于存在离散记录,离散数据集允许记录的字段值是某条记录,这样更容易实现外键连接。

SPL:一种编写简单、运行速度快的数据库语言相关推荐

  1. 编写简单的连接MongoDB数据库C++程序 解决编译C++程序时链接MongoDB动态库失败的问题...

    一. 安装好mongo数据库以后,创建一个用来链接数据库的简单C++程序mon2.cpp,发现很多网站都用这个程序做示例. 不过重点在于如何让这个程序真正可以跑起来显示出来结果,着实费了一番功夫. 1 ...

  2. Ubuntu下C语言程序编写与运行

    Ubuntu下C语言程序编写与运行 安装Ubuntu Ubuntu系统下C程序编写与运行 VC6.0下编译C程序 在Ubuntu下用Makefile方式编程主程序 安装Ubuntu 在Windows环 ...

  3. OSG编写简单程序,运行出现“应用程序无法正常启动(0xc000000d)”的错误

    OSG编译成功了,运行osgviewer.exe  cow.osg可以. 在编写简单的示例程序的时候,出现问题:提示应用程序无法正常启动(0xc000000d). 这是由于所用的库或者DLL和机器编译 ...

  4. 写着简单跑得又快的数据库语言 SPL

    数据库语言的目标 要说清这个目标,先要理解数据库是做什么的. 数据库这个软件,名字中有个"库"字,会让人觉得它主要是为了存储的.其实不然,数据库实现的重要功能有两条:计算.事务!也 ...

  5. python编写程序-30分钟学会用Python编写简单程序

    参与文末每日话题讨论,赠送异步新书 异步图书君 学习目标 知道有序的软件开发过程的步骤. 了解遵循输入.处理.输出(IPO)模式的程序,并能够以简单的方式修改它们. 了解构成有效Python标识符和表 ...

  6. SPL - 写着简单跑得又快的数据库语言

    数据库语言的目标 要说清这个目标,先要理解数据库是做什么的. 数据库这个软件,名字中有个"库"字,会让人觉得它主要是为了存储的.其实不然,数据库实现的重要功能有两条:计算.事务!也 ...

  7. keil debug如何在watch直接修改变量值_零基础学VBA:什么是VBA?如何编写和运行VBA代码?...

    HI,大家好,我是星光,今天咱们来继续学习VBA.在上一章咱们讲了为什么要学习VBA~VBA还值不值得学~学了还有没有用~零基础学VBA编程01:VBA还能不能学?学了还有没有用? 这一章咱们再来简单 ...

  8. 在linux中编写shell脚本文件,如何编写简单的Shell脚本(Script)文件之Linux的基本操作...

    如何编写简单的Shell脚本(Script)文件之Linux的基本操作 新建一个文本文件包含所需要的脚本.举例,我会使用pico编辑器写一个脚本用来运行程序tar,带上必要的可选项可以用来解压从因特网 ...

  9. ROS学习——2编写简单的发布者和订阅者

    ros官网教程:编写简单的发布者和订阅者 目录 c++版 python版 注意 c++版 在新建好的catkin_ws工作空间下建立. cd catkin_ws/src 在该目录下创建自己的功能包:c ...

最新文章

  1. 利用 Arthas 解决启动 HDFS StandbyNameNode 加载 EditLog 慢的问题
  2. tomcat Server.xml Context配置
  3. html5--3.7 input元素(6)
  4. Sturts2中action各项配置的默认值
  5. 搜索提示的实现(仿百度):附源码和在线demo
  6. python类型检查_python【数据类型检查】
  7. Scrapy学习篇(十)之下载器中间件(Downloader Middleware)
  8. Python 常用官方文档整理(中文版)
  9. python脚本编写测试用例
  10. 设备无法连接到你的计算机,此硬件设备未连接到计算机(代码45) | MOS86
  11. Linux修改系统时间
  12. 用c语言解题的程序,C语言实现的数独解题程序
  13. JavaScript 各种事件、方法、参数详解示例及常见问题等(全)
  14. ubuntu 14.04 分辨率调整 -- xrandr命令
  15. 图纸管理系统_图纸文档管理软件系统
  16. 四大Linux备份工具比较与操作实例
  17. 计算机行业研究及2020年策略:聚焦主赛道,投资真成长(84页)
  18. 【STM32】PWM输出原理
  19. 互联网时代,机遇与挑战并存,我们该如何应对?
  20. #遗憾#重重的挫败感再次袭来!!!

热门文章

  1. qt creator源码全方面分析(2-6)
  2. Virtualbox安装Linux虚拟机
  3. windows下使用DOS命令关闭指定端口
  4. 利用stm32来产生1M,1K,1Hz的3个方波(转)
  5. 国产软件出头 | Web版数据库管理工具 SQL Studio颠覆市场
  6. Exception in thread quot;mainquot; org.hibernate.InvalidMappingException: Could not pars
  7. Dokcer 桥接模式原理解析
  8. 关于opa2381放大器芯片
  9. Aspose.Cell组件,实现图表的插入(每一行都有注释+效果图)
  10. java强制类型转换(java强制类型转换有哪些)