Java开发人员来说,SQL这种说明性语言而非面向对象或是命令式编程语言也让其开发成为一大难题中培教育《企业级JAVA高级开发技术实战》培训专家程老师表示,SQL中要写个查询语句是很简单的但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。程老师在这里就Java程序员在写SQL时常犯的错误以及相应的解决方法进行了介绍。
1.NULL抛诸脑后
Java程序员写SQL时对NULL的误解可能是最大的错误。也许是因为并非唯一理由)NULL也称作UNKNOWN。如果被称作UNKNOWN,这还好理解些。另一个原因是,当你从数据库拿东西或是绑定变量时,JDBCSQL NULL Java中的null对应了起来。这样导致了NULL = NULL(SQL)null=null(Java)的误解。
2.Java内存中处理数据
很少有Java开发者能将SQL理解的很好偶尔使用的JOIN,还有古怪的UNION,好吧但是对于窗口函数呢还有对集合进行分组呢许多的Java开发者将SQL数据加载到内存中将这些数据转换成某些相近的集合类型然后再那些集合上面使用边界循环控制结构至少在Java8的集合升级以前执行令人生厌的数学运算
但是一些SQL数据库支持先进的而且是SQL 标准支持的!)OLAP特性这一特性表现更好而且写起来也更加方便一个并不怎么标准的例子就是Oracle超棒的MODEL分句只让数据库来做处理然后只把结果带到Java内存中吧因为毕竟所有非常聪明的家伙已经对这些昂贵的产品进行了优化因此实际上通过将OLAP移到数据库
性能表现.数据库应该比你的算法处理起来更加快而且更加重要的是你不必再去传递数百万条记录了
3. 使用UNION代替UNION ALL
太可耻了,和UNION相比UNION ALL还需要额外的关键字。如果SQL标准已经规定了支持,那么可能会更好点。
移除重复行不仅很少需要(有时甚至是错的,而且对于带很多行的大数据集合会相当慢,因为两个子select需要排序,而且每个元组也需要和它的子序列元组比较。
注意即使SQL标准规定了INTERSECT ALLEXCEPT ALL,很少数据库会实现这些没用的集合操作符。
4.通过JDBC分页技术给大量的结果进行分页操作
大部分的数据库都会支持一些分页命令实现分页效果,譬如LIMIT..OFFSET,TOP..START AT,OFFSET..FETCH语句等。即使没有支持这些语句的数据库,仍有可能对ROWNUM(甲骨文或者是ROW NUMBER() OVER()过滤(DB2,SQL Server2008,这些比在内存中实现分页更快速。在处理大量数据中,效果尤其明显。
5.java内存中加入数据
从SQL的初期开始,当在SQL中使用JOIN语句时,一些开发者仍旧有不安的感觉。这是源自对加入JOIN后会变慢的固有恐惧。假如基于成本的优化选择去实现嵌套循环,在创建一张连接表源前,可能加载所有的表在数据库内存中,这可能是真的。但是这事发生的概率太低了。通过合适的预测,约束和索引,合并连接和哈希连接的操作都是相当的快。这完全是是关于正确元数据在这里我不能够引用Tom Kyte的太多。而且,可能仍然有不少的Java开发人员加载两张表通过分开查询到一个映射中,并且在某种程度上把他们加到了内存当中。
6.在一个临时的笛卡尔积集合中使用 DISTINCT 或 UNION 消除重复项
通过复杂的连接,人们可能会对SQL语句中扮演关键角色的所有关系失去概念。特别的,如果这涉及到多列外键关系的话,很有可能会忘记在JOIN .. ON子句中增加相关的判断。这会导致重复的记录,但或许只是在特殊的情况下。有些开发者因此可能选择DISTINCT来消除这些重复记录。从三个方面来说这是错误的:
它(也许解决了表面症状但并没有解决问题。它也有可能无法解决极端情况下的症状。
对具有很多列的庞大的结果集合来说它很慢。DISTINCT要执行ORDER BY操作来消除重复。对庞大的笛卡尔积集合来说它很慢,还是需要加载很多的数据到内存中。
7. 不使用MERGE语句
这并不是一个过失,但是可能是缺少知识或者对于强悍的MERGE语句信心不足。一些数据库理解其它形式的更新插入(UPSERT)语句, 如 MYSQL的重复主键更新语句,但是MERGE在数据库中确是很强大,很重要,以至于大肆扩展SQL标准,例如SQL SERVER
8. 使用聚合函数代替窗口函数(window functions)
在介绍窗口函数之前,在SQL中聚合数据意味着使用GROUP BY语句与聚合函数相映射。在很多情形下都工作得很好,如聚合数据需要浓缩常规数据,那么就在join子查询中使用group查询。
但是在SQL2003中定义了窗口函数,这个在很多主流数据库都实现了它。窗口函数能够在结果集上聚合数据,但是却没有分组。事实上,每个窗口函数都有自己的、独立的PARTITION BY语句,这个工具对于显示报告太TM好了。
9. 使用内存间接排序
SQLORDER BY语句支持很多类型的表达式,包括CASE语句,对于间接排序十分有用。你可能重来不会在Java内存中排序数据
10. 一条一条的插入大量纪录
JDBC ”懂“批处理(batch),你应该不会忘了它。不要使用INSERT语句来一条一条的出入成千上万的记录,因为每次都会创建一个新的PreparedStatement对象。如果你的所有记录都插入到同一个表时,那么就创建一个带有一条SQL语句以及附带很多值集合的插入批处理语句。你可能需要在达到一定量的插入记录后才提交来保证UNDO日志瘦小,这依赖于你的数据库和数据库设置。