【数据蒋堂】第16期:SQL像英语是个善意的错误

我们知道,SQL长得很像英语,简单的SQL语句直接可以作为英语读。除了SQL外,其它主要程序设计语言都没有这样,语法中就算有英语单词也仅仅是作为某些概念或操作的助记符而已,写出来的是形式化的程序语句(statement)而不是英语句子(sentence)。而SQL不同,它会把整个句子写成符合英语习惯的形式,还会补充很多不必要的介词,比如FROM作为语句的运算主体却被写到后面,GROUP后面要写一个多余的BY。

为什么会这样?很容易想到的理由是希望非程序设计人员也能使用。用户只要会读写英语,就可以写出SQL来查询数据。这显然是个善意的初衷,但结果却不尽如人意。绝大多数业务人员只会用SQL写非常简单的查询,而对于这类查询,应用程序常常都有更为便捷直观的可视化界面来协助,并不需要直接手写语句,这个设计初衷就失去意义。反过来, 经常使用SQL做运算的仍然是程序员,SQL还是一种编程语言,像不像英语对于程序员理解并没有多大差别,反而会带来不小的困难。

事实上,SQL是一种语法非常严格的语言,语句中任何一点不合规的地方就会被解释器拒绝,使用者必须认真学习并遵守其语法规则,这和其它程序设计语言并没什么两样。而自然语言真正的优势在于具有模糊性,可以一定程度接受不严格的语法,但SQL并没有支持这一点,在发明SQL那个年代也实现不了这个特性。

像英语的好处没有体现,坏处却很严重,将语法设计得像自然语言,看起来容易掌握,其实恰恰相反。

贴近自然语言带来的主要坏处是非过程性。程序逻辑一般是分步执行的,用变量记录中间结果,供后面的步骤使用。但自然语言不是这样,两句话之间的引用关系靠少量几个代词维系,不够用且不精确,所以更习惯的做法是把尽量多的任务写在一句话中,复杂情况下就会大量使用从句。在SQL中的表现就是一句话中配有多个动作,SELECT、WHERE、GROUP都拼进去,像WHERE和HAVING其实是一个意思,却要采用两个词以示区别,而查询需求复杂时就会出现多层嵌套的子查询。这种现象在其它程序设计语中是不常见的。

分步是降低理解和执行难度的有效法门,本来挺简单分几步能做到的事情,如果不分步就会很绕。比如要找出销售额超过平均值两倍的客户,自然思维方式就是先算出销售额的平均值,再找出销售额超这个值两倍的客户,两个语句完成。而SQL的写法就需要用子查询写成更长的一句。这个例子还算好懂,只有两层,一般自然语言的从句用来描述两层关系的理解难度还可以接受,但实际复杂的查询涉及到三五层的比比皆是,严重增加理解难度。

不提倡分步,就会导致单句SQL很长。程序员面临的复杂SQL语句,很少以行计,经常是以K计。而同样的100行代码,分成100个语句还是只有1个语句,其复杂度完全不是一个层面的。这种代码理解起来非常困难,好不容易写出来,过两个月后自己都读不懂,而且太长不分步的单句非常难以调试,开发周期也更长。

关于过程性,SQL的拥趸者一直有一个说法:写SQL时用户只要关心要什么,而不必关心怎么做,计算机会自动找解决方案,这样语法本身不需要支持过程性。

这其实是个胡扯!

任何程序语言在某种层次上都具有这个能力,写汇编语言需要关心寄存器和内存的动作,但不必关心更下层的与非门的动作。SQL中不必关心数据在物理存储层面(文件系统、内存和硬盘)的动作,但仍然要关心逻辑层面(表和字段)的运算。SQL语句事实上也在描述运算逻辑,特别是多层嵌套关联的复杂SQL,在描述问题目标的同时,实际上也指明了执行过程,或者倒过来说,在SQL中也只能用指明执行过程的方法来描述问题目标,只不过相对比较高层次一些而已。

不过,SQL只是不提倡分步计算,而并非完全不支持过程性。使用存储过程就相当于分步执行SQL,使用外部程序调用SQL也可以实现过程性,如果不考虑临时表(用于存储中间结果)和数据库IO(外部语言调用SQL时要获得运算结果)的低性能,这些方法在功能上并没什么缺失。但要考虑到数据量导致的性能问题时,还是经常需要编写长SQL才能解决问题。在数据量较小、性能问题不突出时,可以用这些方法来补充SQL的过程性。

原文发布时间为:2017-7-25

本文作者:蒋步星

本文来自合作伙伴“数据蒋堂”,了解相关信息可以关注“数据蒋堂”微信公众号

时间: 2024-07-28 12:44:32

【数据蒋堂】第16期:SQL像英语是个善意的错误的相关文章

数据蒋堂 | SQL像英语是个善意的错误

我们知道,SQL长得很像英语词语,简单的SQL语句直接可以作为英语读.除了SQL外,其它主要程序设计语言都没有这样,语法中就算有英语单词也仅仅是作为某些概念或操作的助记符而已,写出来的是形式化的程序语句(statement)而不是英语句子(sentence).而SQL不同,它会把整个句子写成符合英语习惯的形式,还会补充很多不必要的介词,比如FROM作为语句的运算主体却被写到后面,GROUP后面要写一个多余的BY. 为什么会这样?很容易想到的理由是希望非程序设计人员也能使用.用户只要会读写英语,就

开源大数据周刊-第16期

阿里云E-Mapreduce动态 E-Mapreduce团队 1.4版本(已经发布) 作业运行失败报警 作业并行提交 添加sqoop.shell类型的作业 1.4.1版本(正在研发) 完善失败报警 完善定时任务,增加小时.分钟定时任务 1.5.0版本 (正在研发) 集群整体运行情况的仪表盘 集群状态监控报警 1.6.0版本 交互式查询(支持hive.spark) 资讯 Apache Spark 2.0.0 发布,APIs 更新 该版本主要更新APIs,支持SQL 2003,支持R UDF ,增强

【数据蒋堂】第17期:SQL的困难源于关系代数

在结构化数据处理领域,SQL无疑是应用最广泛的工作语言,不仅被所有关系数据库采用,许多新进的大数据平台也将实现SQL作为目标.但现实是,面对当前纷杂的计算查询需求,SQL在很多方面并不够好用.我们在前面说过SQL的过程性问题,这其实并不是最关键的问题,SQL的更大困难来源于其理论基础,即关系代数. 关系代数是一种代数体系.我们无法在本文的篇幅中严格定义代数体系这个概念,只能通俗地解释.人们为解决某种运算问题,定义了一些数据对象及针对这些数据对象的一套运算规则,确保这些运算的封闭性和自洽性,就可以

【数据蒋堂】第20期:从SQL语法看离散性

所谓离散性,是指集合的成员可以游离在集合之外存在并参与运算,游离成员还可以再组成新的集合.从离散性的解释上可以知道,离散性是针对集合而言的一种能力,离开集合概念单独谈离散性就没有意义了. 离散性是个很简单的特性,几乎所有支持结构(对象)的高级语言都天然支持,比如我们用Java时都可以把数组成员取出来单独计算,也可以再次组成新的数组进行集合运算(不过Java几乎没有提供集合运算类库). 但是SQL的离散性却很差. SQL体系中有记录的概念,但并没有显式的记录数据类型.单条记录被SQL作为只有一条记

【数据蒋堂】第19期:从SQL语法看集合化

SQL作为最常用的结构化数据计算语言,虽然在做一些细致处理时不太方便,但用于描述基本运算还是比Java等高级语言要简单许多.这是因为SQL是一种集合化的语言,而Java等语言不是.我们下面从SQL的语法上看集合化语言的一些特征,为了方便讨论,我们就用Java作为参照语言,其它高级语言是类似的. 集合运算能力 结构化数据经常是批量(以集合形式)出现的,为了方便地计算这类数据,程序设计语言有必要提供足够的集合运算能力. Java等高级语言则没有直接提供集合运算类库,虽然也有数组(相当于集合)数据类型

【数据蒋堂】第18期:SQL用作大数据计算语法好吗?

当前的大数据平台在处理结构化数据时大都仍然以提供SQL语法为主流.兼容SQL的好处是很明显的,SQL的应用非常广泛,会SQL的程序员很多,如果继续采用SQL则可以避免许多学习成本.支持SQL的前端软件也很多,使用SQL的大数据平台很容易融入这个现成的生态圈中.大数据平台打算替代的传统数据库也是SQL语法的,这样兼容性会很好,移植成本相对较低. 但继续使用SQL也有缺点,最大的问题就是难以获得大数据计算最需要的高性能. 我们在前面的文章中提到过,SQL中缺乏一些必要的数据类型和运算定义,这使得某些

【数据蒋堂】第3期:功夫都在报表外-漫谈报表性能优化

应用系统中的报表,作为面向业务用户的窗口,其性能一直被高度关注.用户输入参数后都希望立即就能看到统计查询结果,等个十几二十秒还能接受,等到三五分钟的用户体验就非常恶劣了. 那么,报表为什么会慢,又应当从哪里入手进行性能调优呢? 数据准备 当前应用中的报表大都用报表工具开发,当报表响应太慢时,不明就里的用户就会把矛头指向使用报表工具的开发人员或者报表工具厂商.其实,大多数情况报表的慢只是个表现,背后的原因是数据准备太慢,在数据进入报表环节之前就已经慢了,这时再去优化报表开发或压迫报表工具并没有用处

《数据蒋堂》第9期:报表应用的三层结构

在传统的报表应用结构中,报表工具一般都是与数据源直接连接,并没有一个中间的数据计算层.确实,大部分情况下的报表开发并不需要这一层,相关的数据计算在数据源和呈现环节分别处理就够了.不过,在开发过程中,我们发现,有一部分报表的计算即不适合在数据源也不适合在呈现环节实现,这类报表在数量上并不占多数,但耗用的开发工作量占比却很大. 有过程的计算 报表工具都可以完成计算列.分组排序等运算,有些报表工具还提供了跨行组运算和相对格与集合的引用方案,可以完成颇为复杂的运算. 不过,报表工具中的运算是一种状态式的

【数据蒋堂】第31期:JOIN简化 - 维度对齐

那么问题来了,这显然是个有业务意义的JOIN,它算是前面所说的哪一类呢? 这个JOIN涉及了表Orders和子查询A与B,仔细观察会发现,子查询带有GROUP BY id的子句,显然,其结果集将以id为主键.这样,JOIN涉及的三个表(子查询也算作是个临时表)的主键是相同的,它们是一对一的同维表,仍然在前述的范围内. 但是,这个同维表JOIN却不能用上一期说的写法简化,子查询A,B都不能省略不写. 可以简化书写的原因在于:我们假定事先知道数据结构中这些表之关联关系.用技术术语的说法,就是知道数据