`
wanglizhuang
  • 浏览: 14022 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
最近访客 更多访客>>
社区版块
存档分类
最新评论

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

    博客分类:
  • SQL
 
阅读更多

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(甲骨文)或者是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的 ON DUPLICATE KEY UPDATE 分句。但是MERGE真的是如此强大,在大多数重视扩展SQL标准的数据库,如SQL Server中是很重要的。

  解决方法:

  如果你正在通过链接INERT和UPDATE,或者通过链接SELECT...FOR UPDATE进行UPSERT,然后进行INSERT或者UPDATE,请三思。在冒此风险之外,你还可以选择使用一个简单的MERGE语句进行表达。

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

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

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

  使用窗口函数:

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

  解决方法:

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

 9. 使用内存间接排序

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

  • SQL排序很慢
  • SQL排序办不到

  处理方法:

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

 10. 一条一条的插入大量纪录

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

  处理方法:

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

分享到:
评论

相关推荐

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

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

    java源码包---java 源码 大量 实例

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java源码包2

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    java源码包4

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    java源码包3

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码...

    JAVA_API1.6文档(中文)

    java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    16个目标文件 内容索引:Java源码,初学实例,二进制,文件复制 Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员...

    java开源包10

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包11

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包6

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包4

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包9

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包101

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包5

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

    java开源包8

    LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持很多特性例如文件传输、...

Global site tag (gtag.js) - Google Analytics