下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

Java程序员在写SQL程序时容易范哪些错误?

作者:课课家教育     来源: http://www.kokojia.com点击数:1058发布时间: 2017-09-03 09:30:54

标签: 数据库SQLJava程序员

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

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

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

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

  但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而非面向对象或是命令式编程语言,而且它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统,可以使用相同的结构化查询语言作为数据输入与管理的接口。结构化查询语言语句可以嵌套,这使它具有极大的灵活性和强大的功能。​在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。

 但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而非面向对象或是命令式编程语言,而且它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统,可以使用相同的结构化查询语言作为数据输入与管理的接口。结构化查询语言语句可以嵌套,这使它具有极大的灵活性和强大的功能。​在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。

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

  1.忘掉NULL

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

  对于NULL最大的误解是当NULL被用作行值表达式完整性约束条件时。

  另一个误解出现在对于NULL在NOTINanti-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代替UNIONALL

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

  ①UNION(允许重复)

  ②UNIONDISTINCT(去除了重复)

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

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

  处理方法:

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

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

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

  纠正:

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

  5.在java内存中加入数据

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

  纠正:

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

  6.使用DISTINCT和UNION从一个偶然的笛卡尔积中删除重复

  由于重量级连接的使用,一个人可以松绑对在SQL语句中起作用的所有关系的跟踪.具体来说,如果多列外键关系被加入进来的话,忘掉加入使用JOIN...ON分句的相关谓语是很有可能的。这可能会导致重复的记录,但也可能只发生在异常的情况下。一些开发者可能因此选择使用DISTINCT来移除那些重复的记录。这在三个方面都证明是错误的:

  它(可能)能够治标,但并不治本。极端情况下它也可能练治标的能力也没有。

  对于含有许多列的大型结果集,它的处理是缓慢的。DISTINCT执行了一个ORDERBY的操作来移除重复的记录。

  对于大型的笛卡尔积,它的处理是缓慢的,仍将会把许多的数据加载到内存中。

  解决方法:

  作为首要的规则,当你得到了不想要的重复记录时,常常要重新检查检查你的JOIN谓语。很可能有一个微妙的笛卡尔积在那某一个地方。

  7.不去使用MERGE语句

  这并不是一个真正的错误,但可能是由于某些知识的缺失,或者是对于强大的MERGE语句的某种畏惧。一些数据库知道其他形式的UPSERT语句,例如,MYSQL的ONDUPLICATEKEYUPDATE分句。但是MERGE真的是如此强大,在大多数重视扩展SQL标准的数据库,如SQLServer中是很重要的。

  解决方法:

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

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

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

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

  使用窗口函数:

  ①使SQL更易读(但在子查询中没有GROUPBY语句专业)

  ②提升性能,像关系数据库管理系统能够更容易优化窗口函数

  解决方法:

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

  9.使用内存间接排序

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

  ①SQL排序很慢

  ②SQL排序办不到

  处理方法:

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

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

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

  处理方法:

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

  小编结语:

  更多内容尽在课课家教育!

赞(29)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程