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

  • 技能(任何人都能容易学会命令式编程)

  • 模式(有些人用“模式-模式”,举个例子,模式可以应用到任何地方,而且都可以归为某一类模式)

  • 心境(首先,要写个好的面向对象程序是比命令式程序难的多,你得花费一些功夫)

但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而非面向对象或是命令式编程语言。在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。

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

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 ALL(允许重复)

  • UNION (去除了重复)

移除重复行不仅很少需要(有时甚至是错的),而且对于带很多行的大数据集合会相当慢,因为两个子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日志瘦小,这依赖于你的数据库和数据库设置。

解决方法:

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

原文来源:http://blog.jooq.org/
译者:LianyouCQ, LeoXu, yale8848, 开源中国驻联合国理事, super0555
译文:https://www.oschina.net/translate/10-common-mistakes-java-developers-make-when-writing-sql

IT技术分享社区

个人博客网站:https://programmerblog.xyz

文章推荐程序员效率:画流程图常用的工具程序员效率:整理常用的在线笔记软件远程办公:常用的远程协助软件,你都知道吗?51单片机程序下载、ISP及串口基础知识硬件:断路器、接触器、继电器基础知识

后端技术:Java 程序员常犯的 10 个 SQL 错误!相关推荐

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

    往期热门文章: 1.摸鱼王!2.抖音服务器带宽有多大,才能供上亿人同时刷?3.Spring新版本抛弃JVM,可独立部署,网友:要自立门户???4.记一次因 Redis 使用不当导致应用卡死 bug 的 ...

  2. Java程序员容易犯的10大低级错误

    本文根据java开发人员在编码过程中容易忽视或经常出错的地方进行了整理,总结了十个比较常见的低级错误点,方便大家学习. 1.不能用"=="比较两个字符串内容相等. 2. 对list ...

  3. Java程序员常犯的几类错误

    1.忽视异常 相信很多小伙伴在编程的过程中经常对异常置之不理.针对初学者和有经验的 Java 程序员,最佳实践仍是处理它们.异常抛出通常是带有目的性的,因此在大多数情况下需要记录引起异常的事件.不要小 ...

  4. python编程新手常犯的错误_Python程序员常犯的10个错误

    BY- SENIOR SOFTWARE ENGINEER @TOPTAL About Python 关于Python Python is an interpreted, object-oriented ...

  5. java中级程序员面试题_中级Java程序员常见面试题汇总

    下面是一些中级Java程序员常见面试题汇总,你可以用它来好好准备面试. 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器 ...

  6. Python程序员常犯的十个错误

    不管是在学习还是工作过程中,人都会犯错.虽然Python的语法简单.灵活,但也一样存在一些不小的坑,一不小心,不管是初学者还是资深Python程序员都有可能会栽跟头. 常见错误1:错误地将表达式作为函 ...

  7. 作为Java程序员应该掌握的10项技能

    本文详细罗列了作为Java程序员应该掌握的10项技能.分享给大家供大家参考.具体如下: 1.语法:必须比较熟悉,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知 ...

  8. 初级程序员经常犯的10种错误,网友:工作几年了都还在犯

    初级程序员经常犯的10种错误,网友:工作几年了都还在犯 小编在网上经常容易看见#程序员如何升职#.#程序员的进阶之路#这样的话题,于是我整理了一些网上的资料并结合自己的经验,梳理出了10种初级程序员经 ...

  9. Java程序员应该知道的10个调试技巧

    摘要:调试不仅可以查找到应用程序缺陷所在,还可以解决缺陷.对于Java程序员来说,他们不仅要学会如何在Eclipse里面开发像样的程序,更需要学会如何调试程序.本文介绍了Java程序员必知的10个调试 ...

最新文章

  1. java如何接收邮件_java Exchange服务接收邮件
  2. 音频开发中常见的四个错误
  3. 机器学习实战9-运行Tensorflow(california_housing数据集)
  4. java实现18位校验
  5. 自定义协同程序:CustomYieldInstruction
  6. c#中using 和new
  7. [转]laravel 4之视图及Responses
  8. linux shell pattern,shell 三剑客之 sed pattern 详解
  9. 微软商店 错误代码0x80073CF9
  10. 利用 安装oracle依赖包,使用yum快速安装oracle11g依赖包
  11. 智慧城市大屏可视化(Axure高保真原型)
  12. 自然语言处理面试基础
  13. 海思HI3518E视频处理基础概念《二》----- 视频输入VI和 视频输出VO
  14. linux_主线程子线程退出关系
  15. 【CAD-Web】CAD/DWG的Web化
  16. 什么是面向过程与面向对象
  17. 联发科射频工程师题目_【MTK联发科技射频工程师面试】意外接到联发科人力资...-看准网...
  18. 团队里来了个阿里技术大神!架构师都跪了,没有不服的......
  19. 为什么老师说尽量别用wps
  20. Smart 200系列PLC基础知识总结

热门文章

  1. ASP.NET学习笔记
  2. 移动web开发框架之我见
  3. 打印机每天都要重新连接
  4. 批处理获取exe返回结果
  5. c语言结构体单元测试,C语言结构体单元练习.doc
  6. string中c_str()、data()、copy(p,n)函数的用法
  7. linux 如何查看终端格式,你应该还不知道,Linux终端下的 Markdown 文档查看器
  8. android 文件选择器_Android 开发 打开系统文件、图片、视频等 实现单选多选功能...
  9. python double free_python错误:double free或corruption(out):0x0000000001e4b030
  10. 74HC595芯片使用说明