从 SQL 和 Java 的对比理解集合化,SQL 到底比 Java 优势在哪?

ops/2024/9/25 20:32:02/

同样的数据计算任务,用 SQL 写和用 Java 写,后者常常会长出数倍。代码长不仅仅是写起来很繁琐,也不利于理解整体业务逻辑结构,算法过程都湮没在细节中。
为什么 Java 会比 SQL 长这么多?我们来回答这个问题,并引出程序语言的集合化概念。

首先是针对集合的运算能力,这个很容易理解。
业务逻辑经常面对结构化数据,而结构化数据通常是批量(以集合形式)出现的,要方便计算这类数据,程序设计语言有必要提供足够的集合运算能力。
早期 Java 没有直接提供面向结构化数据的集合运算类库,甚至连象样的结构化数据对象都没有。做个简单计数求和都要写很多行,分组连接这些更是麻烦无比。
SQL 则有比较完善集合运算,如 SUM/COUNT 等聚合运算,WHERE 用于过滤、GROUP 用于分组,写出来的代码就会短小很多。

那么,给 Java 补一些集合运算的库函数不就完了吗?比如,比如说 Java8 之后的 Stream 就有不少,是不是就可以了?
没这么简单!
我们用排序运算举例,在 SQL 中排序简单写成 ORDER BY price 就可以了,你不用关心这个 PRICE 的数据类型。
Java 是一种类型严格的编译语言,同一个函数不能针对不同数据类型工作,就要为不同数据类型分别写一遍排序函数,整数、实数、字符串各自不同,只是麻烦库函数开发者也就罢了,问题是使用者也要指明数据类型,编译器才能找到函数。Java 已经发明了泛型语法来简化写法,但代码中仍然会有一堆尖括号,看着就很乱,影响对业务的理解。

排序可能面对多个参数,比如 SQL 中写 ORDER BY price, quantity。
这个事对 Java 又是个问题。参数个数不同的函数不能混用,这总不能像对付数据类型那样事先把所有参数个数的可能性都穷举一遍。通常的办法就是写个单参数函数,碰到多参数时再临时转换成单参数,比如把这里的 price 和 quantity 拼成一个参数再排序。或者支持集合参数,引用时也得把参数凑成一个集合形式多搞一层。写起来是相当的麻烦。
SQL 没有这样的事,解释型语言可以动态根据数据类型以及个数来决定怎么做。

事还没完,排序还可能针对一个计算式,比如 SQL 中写 ORDER BY price*quantity。这个 price*quantity 并不是在执行这个 SQL 语句之前先计算好的,而是在遍历集合成员才计算的。本质上,price*quantity 是个函数,是一个以当前集合成员为参数的函数,也就是相当于把一个用表达式定义的函数用作了排序运算的参数。
Java 中如果把表达式写到函数的参数中,会在调用前就先计算出来,而不是针对集合成员分别计算。Java 当然允许把一个函数作为参数传递给另一个函数,但写法要麻烦很多,需要事先定义一个函数。

把函数当参数传,又懒得事先定义,这不就是 Lambda 语法吗,Java 现在也支持了啊。
是的,Java 现在有了 Lambda 语法,可以在参数中直接定义匿名函数了。但显然不能写成简单的计算式,编译器无法区别时就会直接给算出来。Lambda 语法仍然是常规函数那一套,要定义参数甚至类型,也有个明显的函数体,只是不起名字而已。而且由于刚才说的数据类型和参数个数问题常常和这个 Lambda 语法搅合到一起,代码更为混乱。
SQL 则把 Lambda 语法化于无形了,甚至都没人把 SQL 这种语法称为 Lambda 语法,但它确实是妥妥地用一个计算式定义了一个函数当参数用。

而且,结构化数据并非简单的单值,而是带有字段的记录。
在 SQL 的表达式参数中引用记录字段时,大多数情况可以直接使用字段名而不必指明字段所在的表,只有在多个同名字段时才需要冠以表名(或表的别名)以示区分。
Java 的 Lambda 语法并不天然知道认得记录,对它来讲就是个参数,取记录的字段(也就是类的成员)要用 dot 操作符,如果表示当前成员的参数名为 it,就要写成 it.price*it.quantity 这种啰嗦的形式。
有了直接引用字段的语法机制后,才可以说是专业面向结构化数据计算的语言。
运算一旦从针对单值变成针对集合,特别是针对结构化数据的集合,麻烦事就多了很多。

说完了吗?并没有。SQL 还支持动态数据结构。
结构化数据计算中,计算结果经常也是有结构的数据,它的结构和运算相关,没办法在代码编写之前就先准备好。所以需要支持动态数据结构的能力。
SQL 中任何一个 SELECT 语句都会产生一个新的数据结构,在代码中可以随意添加删除字段,而不必事先定义结构(类)。Java 这类编译语言又不行,在代码编译前就要把用到的结构(类)都定义好,原则上不能在执行过程中动态产生新的结构。
还有种办法是定义一个复杂的类能够用来描述动态的结构,字段名和值都作为数组成员,然而这已经不是 Java 风格的类了,成员的引用都不能简单地用 dot,而要调用函数,很不方便。除非设计一门新语言,把这种对象作为基础数据类型,才能方便使用。

我们总结一下:集合运算类库,其中参数的类型和数量可以是动态的;化于无形的 Lambda 语法,在其中可以直接引用记录的字段;动态数据结构。
这些我们通称为程序语言的集合化特性!有了集合化特性,才能方便地处理批量的结构化数据。
SQL 中这些看起来理所当然的语法体系,其实背后并没有那么简单,这需要精心的设计。

按这个标准去衡量,Java 本身固然不行,在 Java 上增加再多的类库也不行,基于 Java 设计的新语言 Kotlin 和 Scala 也不满足这标准。其中很关键的化于无形 Lambda 语法,要在解释型语言中才能实现。解释器才知道某个位置的计算式是该先算出值来还是当函数传进去,而编译型语言要写成字符串或者用某种符号体系来区分,这就会破坏代码的简洁性。所以,这些程序语言无论如何不可能像 SQL 一样简洁。
SPL.html" title=esProc SPL>esProc SPL 可以!它是基于 Java 设计的解释型语言,满足上述一切集合化特性。

开源SPL源码地址

SPL下载


http://www.ppmy.cn/ops/115936.html

相关文章

【AI视频】AI虚拟主播制作网站推荐

一、什么是AI虚拟主播? AI虚拟主播是一种利用人工智能技术打造的虚拟主持人,也被称为数字虚拟主持人。它们通常是由人工智能技术和三维建模技术结合而成,可以在各种平台上进行主持工作,如新闻报道、电商直播、综艺娱乐等。 AI虚…

Python 课程19-FastAPI

前言 FastAPI 是一个用于构建 API 的现代化、快速的 Python Web 框架。它基于 Python 的 type hints 构建,能够自动生成 API 文档并提供出色的性能。FastAPI 的设计目标是简单易用、高性能和支持异步操作,因此它非常适合开发高并发的 Web 应用程序和 AP…

电脑如何设置代理IP:详细步骤指南

在网络世界中,代理IP是一种非常实用的工具。它不仅能保护你的隐私,还能访问更多的网络资源。今天,我们就来详细讲解一下如何在电脑上设置代理IP,让你轻松掌握这项技能。 什么是代理IP? 代理IP,简单来说&am…

51单片机 - DS18B20实验1-读取温度

上来一张图,明确思路,程序整体裤架如下,通过单总线,单独封装一个.c文件用于单总线的操作,其实,我们可以把点c文件看成一个类操作,其属性就是我们面向对象的函数,也叫方法&#xff0c…

电线杆上电气组件检测系统源码分享

电线杆上电气组件检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comp…

使用 Internet 共享 (ICS) 方式分配ip

设备A使用dhcp的情况下,通过设备B分配ip并共享网络的方法。 启用网络共享(ICS)并配置 NAT Windows 自带的 Internet Connection Sharing (ICS) 功能可以简化 NAT 设置,允许共享一个网络连接给其他设备。 打开网络设置&#xff1…

在虚幻引擎中创建毛发/头发

在虚幻引擎中创建毛发/头发 , 首先开启两个插件 Groom 和 Alembic Groom Importer 打开蒙皮缓存 导出人物模型 将人物导入Blender , 选择需要种植头发的点 指定并选择 点击毛发 这里变成爆炸头了 , 把数量和长度调一下 切换到梳子模式 调整发型 导出为abc , 文件路径不…

学习国语的时候需要用到什么翻译工具?《维汉翻译通》app现在已经支持国语拼音和维汉词典查单词功能

《维汉翻译通》App是一款免费的翻译工具,专为维吾尔语与中文之间的沟通设计。它不仅是一款翻译应用,也是新疆人学习中文的得力助手。 功能亮点 免费翻译服务:提供快速准确的短文本翻译,无论是日常用语还是专业术语。智能OCR技术&…