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/trans…
近期热文举荐:
1.600+ 道 Java 面试题及答案整顿 (2021 最新版)
2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!
3. 阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!