阅读更多

8顶
5踩

编程语言
Java程序员编程时需要混合面向对象思维和一般命令式编程的方法,能否完美的将两者结合起来完全得依靠编程人员的水准:

  • 技能(任何人都能容易学会命令式编程)
  • 模式(有些人用“模式-模式”,举个例子,模式可以应用到任何地方,而且都可以归为某一类模式)
  • 心境(首先,要写个好的面向对象程序是比命令式程序难的多,你得花费一些功夫)
但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而非面向对象或是命令式编程语言。在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。

下面是Java程序员在写SQL时常犯的错误(没有特定的顺序)。

1.  忘掉NULL

Java程序员写SQL时对NULL的误解可能是最大的错误。也许是因为(并非唯一理由)NULL也称作UNKNOWN。如果被称作UNKNOWN,这还好理解些。另一个原因是,当你从数据库拿东西或是绑定变量时,JDBC将SQL NULL 和Java中的null对应了起来。这样导致了NULL = NULL(SQL)和null=null(Java)的误解。

对于NULL最大的误解是当NULL被用作行值表达式完整性约束条件时。另一个误解出现在对于NULL 在 NOT IN anti-joins的应用中。

解决方法:

好好的训练你自己。当你写SQL时要不停得想到NULL的用法:

  • 这个NULL完整性约束条件是正确的?
  • NULL是否影响到结果?
2.  在Java内存中处理数据

很少有Java开发者能将SQL理解的很好。偶尔使用的JOIN,还有古怪的UNION,好吧,但是对于窗口函数呢?还有对集合进行分组呢?许多的Java开发者将SQL数据加载到内存中,将这些数据转换成某些相近的集合类型,然后再那些集合上面使用边界循环控制结构(至少在Java8的集合升级以前)执行令人生厌的数学运算。

但是一些SQL数据库支持先进的(而且是SQL标准支持的)OLAP特性,这一特性表现更好而且写起来也更加方便。一个(并不怎么标准的)例子就是Oracle超棒的MODEL分句。只让数据库来做处理然后只把结果带到Java内存中吧。因为毕竟所有非常聪明的家伙已经对这些昂贵的产品进行了优化。因此实际上,通过将OLAP移到数据库,你将获得一下两项好处:

  • 便利性。这比在Java中编写正确的SQL可能更加的容易。
  • 性能表现。数据库应该比你的算法处理起来更加快.而且更加重要的是,你不必再去传递数百万条记录了。
解决方法:

每次你使用Java实现一个以数据为中心的算法时,问问自己:有没有一种方法可以让数据库代替为我做这种麻烦事。

3.  使用UNION代替UNION ALL

和UNION相比UNION ALL还需要额外的关键字。如果SQL标准已经规定了支持,那么可能会更好点。

  • UNION(允许重复)
  • UNION DISTINCT (去除了重复)
移除重复行不仅很少需要(有时甚至是错的),而且对于带很多行的大数据集合会相当慢,因为两个子select需要排序,而且每个元组也需要和它的子序列元组比较。

注意即使SQL标准规定了INTERSECT ALL和EXCEPT ALL,很少数据库会实现这些没用的集合操作符。

解决方法:

每次写UNION语句时,考虑实际上是否需要UNION ALL语句。

4.  通过JDBC分页技术给大量的结果进行分页操作

大部分的数据库都会支持一些分页命令实现分页效果,譬如LIMIT..OFFSET,TOP..START AT,OFFSET..FETCH语句等。即使没有支持这些语句的数据库,仍有可能对ROWNUM(Oracle)或者是ROW NUMBER()、OVER()过滤(DB2、SQL Server2008等),这些比在内存中实现分页更快速。在处理大量数据中,效果尤其明显。

解决方法:

仅仅使用这些语句,那么一个工具(例如JOOQ)就可以模拟这些语句的操作。

5.  在Java内存中加入数据

从SQL的初期开始,当在SQL中使用JOIN语句时,一些开发者仍旧有不安的感觉。这是源自对加入JOIN后会变慢的固有恐惧。假如基于成本的优化选择去实现嵌套循环,在创建一张连接表源前,可能加载所有的表在数据库内存中,这可能是真的。但是这事发生的概率太低了。通过合适的预测,约束和索引,合并连接和哈希连接的操作都是相当的快。这完全是是关于正确元数据(在这里我不能够引用Tom Kyte的太多)。而且,可能仍然有不少的Java开发人员加载两张表通过分开查询到一个映射中,并且在某种程度上把他们加到了内存当中。

解决方法:

假如你在各个步骤中有从各种表的查询操作,好好想想是否可以表达你的查询操作在单条语句中。

6.  在一个临时的笛卡尔积集合中使用 DISTINCT 或 UNION 消除重复项

通过复杂的连接,人们可能会对SQL语句中扮演关键角色的所有关系失去概念。特别的,如果这涉及到多列外键关系的话,很有可能会忘记在JOIN .. ON子句中增加相关的判断。这会导致重复的记录,但或许只是在特殊的情况下。有些开发者因此可能选择DISTINCT来消除这些重复记录。从三个方面来说这是错误的:

  • 它(也许)解决了表面症状但并没有解决问题。它也有可能无法解决极端情况下的症状。
  • 对具有很多列的庞大的结果集合来说它很慢。DISTINCT要执行ORDER BY操作来消除重复。
  • 对庞大的笛卡尔积集合来说它很慢,还是需要加载很多的数据到内存中。
解决方法:

根据经验,如果你获得了不需要的重复记录,还是检查你的JOIN判断吧。可能在某个地方有一个很难觉察的笛卡尔积集合。

7.  不使用MERGE语句

这并不是一个过失,但是可能是缺少知识或者对于强悍的MERGE语句信心不足。一些数据库理解其它形式的更新插入(UPSERT)语句, 如 MYSQL的重复主键更新语句,但是MERGE在数据库中确是很强大,很重要,以至于大肆扩展SQL标准,例如SQL SERVER。

解决方法:

如果你使用像联合INSERT和UPDATE或者联合SELECT .. FOR UPDATE然后在INSERT或UPDATE等更新插入时,请三思。你完全可以使用一个更简单的MERGE语句来远离冒险竞争条件。

8.  使用聚合函数代替窗口函数(window functions)

在介绍窗口函数之前,在SQL中聚合数据意味着使用GROUP BY语句与聚合函数相映射。在很多情形下都工作得很好,如聚合数据需要浓缩常规数据,那么就在join子查询中使用group查询。

但是在SQL2003中定义了窗口函数,这个在很多主流数据库都实现了它。窗口函数能够在结果集上聚合数据,但是却没有分组。事实上,每个窗口函数都有自己的、独立的PARTITION BY语句,这个工具对于显示报告太好了。

使用窗口函数:

  • 使SQL更易读(但在子查询中没有GROUP BY语句专业)
  • 提升性能,像关系数据库管理系统能够更容易优化窗口函数
解决方法:

当你在子查询中使用GROUP BY语句时,请再三考虑是否可以使用窗口函数完成。

9.  使用内存间接排序

SQL的ORDER BY语句支持很多类型的表达式,包括CASE语句,对于间接排序十分有用。你可能重来不会在Java内存中排序数据,因为你会想:

  • SQL排序很慢
  • SQL排序办不到
解决方法:

如果你在内存中排序任何SQL数据,请再三考虑,是否不能在数据库中排序。这对于数据库分页数据十分有用。

10.  一条一条地插入大量记录

JDBC“懂”批处理(batch),你应该不会忘了它。不要使用INSERT语句来一条一条的出入成千上万的记录,(因为)每次都会创建一个新的PreparedStatement对象。如果你的所有记录都插入到同一个表时,那么就创建一个带有一条SQL语句以及附带很多值集合的插入批处理语句。你可能需要在达到一定量的插入记录后才提交来保证UNDO日志瘦小,这依赖于你的数据库和数据库设置。

解决方法:

总是使用批处理插入大量数据。

相关书籍

一些讨论类似主题的相关书籍:


英文原文:10 Common Mistakes Java Developers Make when Writing SQL  / 译文:OSChina
8
5
评论 共 11 条 请登录后发表评论
11 楼 u013339730 2014-07-04 11:48
[/size][size=large]
10 楼 为spring而生 2013-08-12 20:56
表达可以再明了些那就更好了
9 楼 lvwenwen 2013-08-09 02:29
写得不错!
8 楼 黑小子 2013-08-08 09:01
不是很明了
7 楼 carlos 2013-08-07 17:55
享受生活 写道
中文水平像机器翻译,一个问题说不到核心点上。

6 楼 Ethan.Lu 2013-08-07 17:46
感觉没看明白
5 楼 享受生活 2013-08-07 15:14
中文水平像机器翻译,一个问题说不到核心点上。
4 楼 追风IT 2013-08-06 21:58
写的很好,学习了
3 楼 留下的祝福 2013-08-06 09:20
hehui082452239 写道
union all把数据结构相同的两个表合并成一个表,允许重复的。
union 把数据结构相同的两个表合并成一个表,相同的数据合并成一条。

在这里允许重复的叫并集,不允许重复的叫交集!
2 楼 hehui082452239 2013-08-05 22:22
union all把数据结构相同的两个表合并成一个表,允许重复的。
union 把数据结构相同的两个表合并成一个表,相同的数据合并成一条。
1 楼 freezingsky 2013-08-05 10:53
写得不错!

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • Java程序员在写SQL程序时候常犯的10个错误_.docx

    Java程序员在写SQL程序时候常犯的10个错误_.docx

  • Java 程序员容易犯的10个SQL错误

    本文介绍了Java 程序员容易犯的10个SQL错误。具有很好的参考价值,下面跟着小编一起来看下吧

  • java程序员常见的sql错误

    当Java程序员在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。下面我们来看看这几个常见的错误吧

  • Java 程序员在写 SQL 程序时候常犯的 10 个错误

    Java程序员编程时需要混合面向对象思维和一般命令式编程的方法,能否完美的将两者结合起来完全得依靠编程人员的水准: 技能(任何人都能容易学会...但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而

  • Java程序员在写SQL程序时候常犯的10个错误

    Java程序员在写SQL程序时候常犯的10个错误

  • Java 程序员常犯的 10 个 SQL 错误!

    点击关注公众号,Java干货及时送达Java程序员编程时需要混合面向对象思维和一般命令式编程的方法,能否完美的将两者结合起来完全得依靠编程人员的水准:技能(任何人都能容易学会命令式编程)模...

  • java程序员在写XQL程序时候常犯的10个错误

    1.忘掉NULL;2.在Java内存中处理数据;3. 使用UNION代替UNION ALL;...6.在一个临时的笛卡尔积集合中使用 DISTINCT 或 UNION 消除重复项;7. 不使用MERGE语句;(转载于新浪微博@数据挖掘与数据分析)

  • Java程序员在面试中不通过的五个原因

    有哪些问题是初入职场的Java程序员在面试中最容易犯的呢?下面,我总结了Java程序员在面试中不通过的五个原因,作为大家的参考。 1、讲话没有重点 换句话说,就是废话连篇,言之无物。如果你不能简洁扼要的解释...

  • 中高级Java程序员,你不得不掌握的基本功,挑战20k+

    3.3 Java中super关键字与final关键字3.4 final修饰的对象,有几种初始化方式3.5 Java中方法的重载(Overload)与方法的覆盖(Override)3.6 Java基础知识总结,干货来啦3.7 Java基础面试题干货系列(一)3.8 Java中...

  • Java程序员入职指南-北漂Java程序员入职五个月的收获总结

    本文主要分享博主从事Java开发五个月的成长与收获。对于还未入职的小白来说,对工作充满期待和迷茫,不知道进公司该干什么,leader会安排什么任务。如果你还未入职,希望这篇文章可以帮到你。

  • 10万字208道Java经典面试题总结(附答案)

    JDK中包含JRE,JDK中有一个名为jre的目录,里面包含两个文件夹bin和lib,bin就是JVM,lib就是JVM工作所需要的类库。 2、== 和 equals 的区别是什么? 对于基本类型,==比较的是值; 对于引用类型,==比较的是地址...

  • sqlapi4j:一个简单的面向 SQL 的 DSL,用于从 Java 访问数据库

    这一直是程序员头痛的根源,我们认为在使用持久层时忽略数据库的技术性质是错误的。 使用 sqlapi4j,我们从数据库/SQL 的角度来解决问题。 我们创建了一个 DSL,我们希望它看起来和行为都像普通的 SQL,因此遵循...

  • Java程序员掉发系列——程序员必须认识的英文单词(汇总)

    程序员必须懂的英语单词,做程序员这行实在是离不开英语,需要懂的英语单词有很多。下面是博主整理的程序员必须懂的英语单词,以供大家学习参考。

  • 美国Java程序员收入和疫情期间面试心得体会

    第一,美国Java程序员目前的工作形式非常好。虽然现在还是在疫情期间,但是明显工作机会和岗位非常多,可以说各个公司都在大量的招人。尤其是对有经验的程序员来说,接电话都接不过来。这两个星期,几乎每天找上门的...

  • 2年工作经验的Java程序员面试经历

     很多公司会要求笔试,笔试的内容是一些Java基础的内容也可能有些高级的java内容,面试的时候会根据笔试内容提问,同时也会根据简历对于面试者提出相关的项目经验,主要是在面试的这个过程中,把自己的优势充分的...

  • pendulum-2.1.2-cp39-cp39-win32.whl.rar

    python whl离线安装包 pip安装失败可以尝试使用whl离线安装包安装 第一步 下载whl文件,注意需要与python版本配套 python版本号、32位64位、arm或amd64均有区别 第二步 使用pip install XXXXX.whl 命令安装,如果whl路径不在cmd窗口当前目录下,需要带上路径 WHL文件是以Wheel格式保存的Python安装包, Wheel是Python发行版的标准内置包格式。 在本质上是一个压缩包,WHL文件中包含了Python安装的py文件和元数据,以及经过编译的pyd文件, 这样就使得它可以在不具备编译环境的条件下,安装适合自己python版本的库文件。 如果要查看WHL文件的内容,可以把.whl后缀名改成.zip,使用解压软件(如WinRAR、WinZIP)解压打开即可查看。 为什么会用到whl文件来安装python库文件呢? 在python的使用过程中,我们免不了要经常通过pip来安装自己所需要的包, 大部分的包基本都能正常安装,但是总会遇到有那么一些包因为各种各样的问题导致安装不了的。 这时我们就可以通过尝试去Python安装包大全中(whl包下载)下载whl包来安装解决问题。

  • Nginx配置文件中FastCGI相关参数理解

    Nginx配置文件中FastCGI相关参数理解

  • Pillow-8.4.0-cp310-cp310-win32.whl.rar

    python whl离线安装包 pip安装失败可以尝试使用whl离线安装包安装 第一步 下载whl文件,注意需要与python版本配套 python版本号、32位64位、arm或amd64均有区别 第二步 使用pip install XXXXX.whl 命令安装,如果whl路径不在cmd窗口当前目录下,需要带上路径 WHL文件是以Wheel格式保存的Python安装包, Wheel是Python发行版的标准内置包格式。 在本质上是一个压缩包,WHL文件中包含了Python安装的py文件和元数据,以及经过编译的pyd文件, 这样就使得它可以在不具备编译环境的条件下,安装适合自己python版本的库文件。 如果要查看WHL文件的内容,可以把.whl后缀名改成.zip,使用解压软件(如WinRAR、WinZIP)解压打开即可查看。 为什么会用到whl文件来安装python库文件呢? 在python的使用过程中,我们免不了要经常通过pip来安装自己所需要的包, 大部分的包基本都能正常安装,但是总会遇到有那么一些包因为各种各样的问题导致安装不了的。 这时我们就可以通过尝试去Python安装包大全中(whl包下载)下载whl包来安装解决问题。

  • yolo算法-刹车灯探测器数据集-1070张图像带标签-交通信号灯.zip

    yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值

Global site tag (gtag.js) - Google Analytics