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完整性约束条件是正确的?
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 和WXCEPT ALL,很少数据库会实现这些没用的集合操作符。
解决办法:
每次写UNION语句时,考虑实际上是否需要UNION ALL 语句。
4、通过JDBC分页技术给大量的结果进行分页操作
大部分的数据库都会支持一些分页命令实现分页效果,譬如 limit…offset,top…start at , offset…fetch语句等。即使没有支持这些语句的数据库,仍有可能对rownum(oracle)或者是rownumber()、over()过滤(DB2、sql server2008等),这些比在内存中实现分页更快速。在处理大量数据中,效果尤其明显。
解决办法:
仅仅使用这些语句,那么一个工具(例如:jooq)就要以模拟这些语句的操作。
5、在java内存中加入数据
从sql的初期开始,当在sql中使用join语句时,一些开发者仍旧有不安的感觉。这是源自对加入join后变慢的因有恐惧。
假如基于成本的,优化选择去实现嵌套循环,在创建一张连接表源前,可能加载所有的表在数据库内存中,这可能是真的。但是这事发生的概率太低了。通过合适的预测,约束和索引,合并连接和哈希连接的操作都是相当的快。这完全是关于正确元数据。而且,可能仍然有不少的java开发人员加载两张表通过分开查询到一个映射中,并且在某种程序上把他们加载到了内存当中。
解决办法:
假如你在各个步骤中有从各种表的查询操作,好好想想是否可以表达你的查询操作在单条语句中。
6、在一个临时的笛卡尔积集合中使用distinct或union消除重复项
通过复杂的连接,人们可能会对sql语句中扮演关键角的所有关系失去概念。特别的,如果这涉及到多列外键关系的话,很有可能在特殊的情况下。有些开发者因此可能选择distinct来消除这些重复记录。从三个方面来说,这是错误的:
它解决了表面症状但并没有解决问题。它有可能无法解决极端情况下的症状。
对具有很多列的庞大的结果集合来说它很慢。distinct要很乖order by 操作来消除重复。
对庞大的笛卡尔积集合来说它很慢,还是需要加载很多的数据到内存中。
解决办法:
根据经验,如果你获得了不需要的重复记录,还检查你的join判断吧。可能在某个地方有一个很难觉察的笛卡尔积集合。
7、不使用MERGE语句
这并不 一个过失,但是可能是缺少知识或者对于强悍的merge语句信心不足。一些数据库理解其它形式的更新插入(upsert)语句,如mysql的重复主键更新语句,但是merge在数据库中确是很强大,很重要,以至于大肆扩展sql标准,例如:sqlserver。
解决办法:
如果你使用像联合insert和update或者联合select… for update然后在insert或update等更新插入时,请三思。你完全可以使用一个更简单的merge语句来远离冒险竞争条件。
8、使用聚合函数代替容器函数
在介绍窗口函数之前,在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语句来一条一条的插入成千上万的记录,因为每次都会创建一个新的prepareStatement对象。如果你的所有记录都插入到同一个表时,那么就创建一个带有一条sql语句以及附带很多值集合的插入批处理语句。你可能需要在达到一定量的插入记录后者提交来保证UNDO日志瘦小,这依赖于你的数据库和数据库设置。
解决办法
使用批量插入大量数据。
内容出处:https://mp.weixin.qq.com/s?__biz=MzU3NDg0MTY0NQ==&mid=2247493619&idx=1&sn=570ee412404815e3befa390a6d694558&chksm=fd2e91b1ca5918a703ec0a91d6b2f48f09576c84f8a4ba1302f24f0c35437e6d3ff7be67efac&scene=132#wechat_redirect