`
shinepaopao
  • 浏览: 145246 次
社区版块
存档分类
最新评论

Java 程序员容易犯的10个SQL错误

    博客分类:
  • Java
阅读更多

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的重复主键更新语句,但是MERGE在数据库中确是很强大,很重要,以至于大肆扩展SQL标准,例如SQL SERVER。

解决之道:

如果你使用像联合INSERT和UPDATE或者联合SELECT .. FOR UPDATE然后在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日志瘦小,这依赖于你的数据库和数据库设置。

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

6
6
分享到:
评论
6 楼 narutolby 2013-09-15  
“每次都会创建一个新的PreparedStatement对象”,PreparedStatement相当于对sql进行了编译,每次执行,只需要改相应的变量就行,不会每次都创建的。
5 楼 MrCrapBag 2013-09-11  
e241138 写道
第2条持怀疑态度。

大数据的场景下,肯定不能再内存里处理。性能很低不说,搞不好就内存溢出
4 楼 ray_yui 2013-09-10  
e241138 写道
第2条持怀疑态度。

有这样的情景的,项目中有遇到过,因为一个or查询的关系,导致10秒以上才能查询到数据,最后优化成查询两次然后再做一个并集,时间降到了3秒左右,当然因情况而定
3 楼 e241138 2013-09-10  
第2条持怀疑态度。
2 楼 CEO_JAVA 2013-09-10  
写的不错,都是工作中常见的
1 楼 ray_yui 2013-09-10  
感谢分享,学习学习

相关推荐

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

    以下是根据标题和描述中提到的几点,对Java程序员在SQL编程中常犯错误的详细解析: 1. 忽视NULL的特殊性 NULL在SQL中的含义是未知,与Java中的null不同。Java程序员经常混淆这两个概念,尤其是在使用NULL作为比较...

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

    Java程序员在编写SQL程序时,由于SQL语言的特性和与Java的差异,常常会遇到一些常见错误。以下是对这些错误的详细分析和解决方案: 1. 忘记处理NULL值 NULL在SQL中的处理方式与Java中不同,容易引发混淆。Java中的...

    基础SQL_java程序员面试试题

    对于Java程序员来说,掌握SQL是必要的,因为许多Java应用都需要与数据库进行交互。 1. 构造函数:在Java中,构造函数是一个特殊的方法,它的名字必须与类名相同,没有返回类型,并且主要用于初始化类的对象。当一个...

    Java程序员面试笔试宝典

    数据库连接和SQL查询也是Java程序员面试中的常见话题。书中的这部分可能会讲解JDBC(Java Database Connectivity)API的使用,以及如何编写高效的SQL语句进行数据查询、插入、更新和删除操作。 在面向对象设计方面...

    挑战java程序员系列教程

    在Java编程领域,"挑战java程序员系列教程"是一个旨在提升和测试开发者技能的资源。本教程涵盖了Java语言的核心概念以及实际应用,帮助初学者和有经验的程序员深入理解Java编程的各个方面。Java作为一种广泛使用的...

    java程序员考试题库

    ### Java程序员考试题库知识点详解 #### 一、基础知识练习概览 本章节涵盖了Java的基础知识,主要包括Java入门、数据类型和运算符等关键概念。这些知识点对于初学者来说至关重要,同时也是进阶学习的重要基石。 #...

    SUN JAVA程序员模拟题

    ### SUN JAVA程序员模拟题知识点解析 #### 题目1: JDK组成部分 - **知识点**:JDK(Java Development Kit)组成 - **解析**:JDK主要由以下几个部分组成: - **Java编程语言**:Java编程语言是用于编写Java应用...

    一个Java程序员应该掌握的10项技能

    ### 一个Java程序员应该掌握的10项技能详解 #### 1. 语法 作为Java程序员,必须熟悉Java语言的基本语法。在实际编程过程中,能够根据集成开发环境(IDE)提供的错误提示信息迅速识别出语法错误,并且知道如何进行...

    疯狂java程序员的基本修养

    《疯狂Java程序员的基本修养》随书光盘的内容涵盖了成为一名优秀Java程序员所需掌握的诸多关键知识点。这份资源旨在帮助开发者全面提升其在Java领域的专业素养,包括但不限于编程基础、面向对象设计原则、异常处理、...

    java程序员必读 java程序员必读

    对于想要成为Java程序员的人来说,掌握其基础知识至关重要。本篇文章将深入探讨Java编程的基础概念,帮助初学者理解并掌握Java的核心知识。 首先,我们来了解Java语言的基础。Java是一种面向对象的编程语言,它的...

    java程序员初学20道题

    ### Java程序员初学20道题知识点解析 #### 1. Java初学者习题20道 本部分内容涉及了Java编程的基础概念和技术要点,旨在帮助初学者系统地掌握Java编程的核心知识。 #### 2. 如何看待Java构造函数的执行 在Java中...

    java程序员常见的sql错误

    然而,许多 Java 程序员在编写 SQL 语句时经常犯的一些错误。这些错误可能会导致程序的性能下降、数据的损失或安全漏洞。 错误 1: 不使用批量更新 在编写 SQL 语句时,Java 程序员最常见和最大的一个错误就是忘记...

    中兴通java程序员面试题(高)

    Java程序员在面试中可能会遇到各种复杂的问题,这些题目旨在测试候选人的基础知识、编程技能以及对Java生态系统的理解。以下是对给定题目的一些详细解释: 1. **异常分类**:Java中的异常分为检查型异常(Exception...

    java程序员必备技能(为java学习引航)

    ### Java程序员必备技能详解 #### 一、语法基础 对于一名Java程序员而言,掌握扎实的语法基础至关重要。在日常开发过程中,经常会遇到IDE提示的语法错误。这时,开发者需要能够根据错误信息迅速判断出问题所在,并...

    java程序员面试笔试试题.pdf,这是一份不错的文件

    【Java程序员面试知识点详解】 1. **Java程序的编译过程**:Java程序在编写完成后,需要通过Java编译器(javac)进行编译,生成的是字节码(byte code),而不是机器码(machine code)或DLL。字节码是平台无关的,...

    程序员比用的sql工具

    3. **智能感应提示**:这是一种常见的代码编辑器功能,它能提供自动补全和语法高亮,帮助程序员快速编写和检查SQL语句,减少错误并提高编写效率。 4. **在线升级**:这意味着工具的开发者会定期发布更新和修复,...

    Java程序员要掌握的十个JSP中的标签库

    本文将深入探讨十个JSP标签库,帮助Java开发者更好地理解和利用这些库来增强JSP应用程序的功能。 首先,"Standard"库是所有JSP开发者必须掌握的基础库,它提供了对JSP核心功能的大量增强,比如XML操作、SQL支持、...

    JAVA程序员面试问题

    Java程序员应该了解并应用一些基本的安全编程原则,如输入验证、权限控制、加密敏感数据、避免SQL注入和XSS攻击等。同时,熟悉OWASP(开放Web应用程序安全项目)的指导原则,可以帮助开发者识别和防止常见的安全漏洞...

Global site tag (gtag.js) - Google Analytics