关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java开发者编写SQL语句时常见的10种错误(1)

    Java开发者编写SQL语句时常见的10种错误(1)

    2015-10-16 00:00:00 出处:ITJS
    分享

    Java开发者编写SQL语句时常见的10种错误

    Java开发者对于面向对象编程思维与命令行编程思维的协调程度,取决于他们如下几种能力的水平:

    技巧(任何人都可以编写命令行形式的代码) 教条(有的人使用“模式 - 模式”的方式,即模式无处不在,并以名字作为标识) 情绪状况(在初期,真正面向对象形式的代码比起命令式代码会更加难懂。)

    但是,当Java开发人员编写SQL语句时,一切都变得不同了。SQL是一种说明式语言,与面向对象思想和命令式思想无关。在SQL语言中,查询非常容易表达。但它也不是那么容易以最佳或最正确地方式编写出来。开发人员不仅需要重新思考自己的编程模式,还需要从集合论的角度进行深入思考。

    以下是Java开发人员使JDBC或jOOQ编写SQL语句时,几种常见的错误(排名不分先后)

    1.忘记了NULL

    误解NULL的含义可能是Java开发人员编写SQL最常犯的错误。这有可能是因为NULL也被称为UNKNOWN,但也有其他的原因。当然假如它只被叫做UNKNOWN,会更容易理解一些。另一个原因是,JDBC在获取数据,或绑定变量时,SQL中的NULL被映射到Java中的null。这可能会导致人们认为类似Java中null==null的情况,SQL中也存在NULL= NULL。

    一个更离奇的误解NULL的例子是,当NULL谓词用于行值表达式时。

    另一个微妙的问题产生与对NOTIn 反连接中NULL含义的误解。

    解决办法

    不断的训练自己。要时刻明确NULL的含义,每次你写SQL时,都要考虑:

    对于NULL来说谓词是否正确 NULL是否影响该函数的结果

    2.在Java内存中处理数据

    一些Java开发者十分了解SQL特性。偶尔JOIN,零散的UNION,没什么问题。但假如遇到视窗功能,结果集分组等情况又怎么样呢 很多Java开发人员会把SQL数据加载到内存,把数据转换成一些适合的集合类型,以十分冗长的循环结构在集合上执行恼人数学运算(至少在Java 8改进容器之前是这样的)。

    但一些SQL数据库除了支持SQL标准外,还支持先进的OLAP特性,执行效率更好,且更容易编写。一个非标准的例子就是甲骨文的MODEL子句。只是让数据库进行数据处理过程,将最终获取的结果加载到Java内存中。因为一些非常聪明的人已经优化了这些昂贵的产品。所以,事实上,通过向OLAP数据库上进行迁移,您将得到两个好处:

    简洁。它可能使得在SQL中编写正确代码会比在Java中相对容易 性能。该数据库将可能比你的算法要快。更重要的是,你不必再通过网络传输数百万条记录。

    解决办法

    每次你在Java中实现以数据为中心的算法时,要试着问问自己:有没有办法让数据库执行这些工作,而只把结果交付给我

    3.尽量使用UNION,而不是UNION ALL

    相对于UNION,UNION ALL需要额外的关键字显得相形见绌。假如在SQL标准已定义如下支持,那将会好很多:

    UNION(允许重复) UNION DISTINCT(去掉重复)

    一般很少需要去除重复(有时去重甚至是错误的),而且对于具有很多列的大结果集,它往往很慢,因为这两个子查询需要排序,每个元组都需要与随后的元组进行比较。

    需要注意的是,即使SQL标准指定了INTERSECTALL和EXCEPTALL,但几乎没有任何数据库实现这些用处不大的操作。

    解决办法

    你每次写到UNION时,要考虑下你是否实际上想写的是UNIONALL。

    4.使用JDBC分页功能将大量结果分页

    大多数数据库都支持通过LIMIT.. OFFSET,TOP .. START AT、OFFSET.. FETCH等子句以某种方式对结果进行分页。在没有对这些子句的支持下,但仍然有ROWNUM(Oracle)或ROW_NUMBER()OVER()(DB2,SQL Server 2008和更低版本),这比在内存中分页要快得多。而且这对于大数据集更是明显。

    解决办法

    只要使用那些子句或工具(如jOOQ),可以为你模拟上述分页子句。

    5.将Java内存中实现连接

    从SQL的发展的初期,一些开发商在面对SQL连接时仍然有一种不安的感觉。一直存在着一种固有的恐惧---JOIN速度缓慢。假如基于成本的优化器选择执行嵌套循环,创建一个连接表源之前,加载完整表到数据库内存,那速度确实十分缓慢。但很这少发生。通过适当的谓词,约束和索引,MERGEJOIN和 HASHJOIN操作是非常快的。这与正确的元数据相关(我不用再举Tom Kyte的例子了)。然而,也有仍然可能有不少Java开发人要会从单独的查询中加载两个表到map容器中,在java内存中以某种方式进行连接操作。

    解决办法

    假如你从多个步骤的多个表中进行了SELECT操作,那要慎重考虑一下是否可以在一条语句中表达你所需要的查询功能。

    6.使用DISTINCT或UNION从一个笛卡尔积中删除重复

    冗长连接的存在,会导致SQL语句中起作用的关系显得十分松散。具体地,假如涉及到多列外键关系,很有可能忘记在JOINON子句上添加谓词。这可能会导致重复的记录,但也许只在特殊情况下。然后一些开发者可能会选择使用DISTINCT再次删除这些重复记录。这种错误有三种危害:

    可能治标不治本。甚至在某些边缘情况下,标都治不了 这在有很多列的大结果集上会十分的缓慢。DISTINCT会执行ORDER BY操作来删除重复。 这在大型笛卡尔积中也十分的缓慢,因为这样做仍然会导致在内存中加载大量数据。

    解决办法

    作为一个经验法则,当你得到不想要的重复结果时,应该首先检查你的连接谓词。因为有可能是在某个地方存在着一个不易察觉的笛卡尔积。

    7.不使用MERGE语句

    严格意义上讲,这不是一个真正的错误,可能只是对于功能强大的MERGE语句缺乏足够的认知或存在着某种恐惧而已。有些数据库包括其他形式的UPSERT 语句,如MySQL的ONDUPLICATE KEY UPDATE子句。但MERGE真的十分强大,最重要的是在数据库中,它在很大程度上扩展了SQL标准,如SQL Server。

    解决办法

    假如你通过链接INSERT和UPDATE或链接SELECT... FOR UPDATE来实现UPSERTING,那么你要多想一想。抛开与运行条件的风险,你也许可以使用一个简单的MERGE语句来达到目的。

    8.使用了聚合函数,而不是窗体功能

    引入窗函数之前,使用GROUPBY子句与投影聚合函数是汇总数据的唯一方式。这在大部分情况下都十分有效,假如聚集后的数据需要由常规的数据进行补充,该分组的查询可以置于连接子查询中。

    但是,SQL:2003定义了窗口功能,目前很多主流的数据库厂商也纷纷实现了窗口功能。窗口功能可以聚集结果集中未被分组的数据。事实上,每个窗口的功能支持自身独立的PARTITIONBY子句,这对于报表类应用是一个非常有用的工具。

    使用窗口功能将:

    导致更多的可读性SQL(减少子查询中非专用GROUP BY子句的存在) 提高性能,作为一个RDBMS很可能更容易优化其窗口功能。

    解决办法

    当你在一个子查询写一个GROUPBY子句时,仔细想想这是否能用一个窗口函数来完成。

    9.使用内存排序法进行间接排序

    在SQLORDER BY子句支持多种类型的表达式,包括CASE语句,这对间接排序非常有用。你应该永远可能在Java内存中对数据进行排序,因为你认为:

    SQL排序太慢 SQL排序不能做到这一点

    解决办法

    假如你在内存中对任何SQL数据进行排序,请仔细想想,你是否能把排序迁移至数据库中。这和将分页迁移至数据库中的原因一样。

    10 一个接一个的插入大量的记录

    JDBC包含了批处理,而且你应该使用它。面对成千上万的记录,切勿为每一条记录都创建一个新的PreparedStatement来进行插入操作。假如你要将所有记录都插入到同一个表,使用单一的SQL语句和多个绑定值集合建立一个批处理的INSERT语句。根据您的数据库和数据库配置,您可能需要在一定数量的插入的记录后进行提交,为了保持UNDO日志不过分庞大。

    解决办法

    始终批量插入大型数据集。

    Java开发者编写SQL语句时常见的10种错误

    Java开发者对于面向对象编程思维与命令行编程思维的协调程度,取决于他们如下几种能力的水平:

    技巧(任何人都可以编写命令行形式的代码) 教条(有的人使用“模式 - 模式”的方式,即模式无处不在,并以名字作为标识) 情绪状况(在初期,真正面向对象形式的代码比起命令式代码会更加难懂。)

    但是,当Java开发人员编写SQL语句时,一切都变得不同了。SQL是一种说明式语言,与面向对象思想和命令式思想无关。在SQL语言中,查询非常容易表达。但它也不是那么容易以最佳或最正确地方式编写出来。开发人员不仅需要重新思考自己的编程模式,还需要从集合论的角度进行深入思考。

    以下是Java开发人员使JDBC或jOOQ编写SQL语句时,几种常见的错误(排名不分先后)

    1.忘记了NULL

    误解NULL的含义可能是Java开发人员编写SQL最常犯的错误。这有可能是因为NULL也被称为UNKNOWN,但也有其他的原因。当然假如它只被叫做UNKNOWN,会更容易理解一些。另一个原因是,JDBC在获取数据,或绑定变量时,SQL中的NULL被映射到Java中的null。这可能会导致人们认为类似Java中null==null的情况,SQL中也存在NULL= NULL。

    一个更离奇的误解NULL的例子是,当NULL谓词用于行值表达式时。

    另一个微妙的问题产生与对NOTIn 反连接中NULL含义的误解。

    解决办法

    不断的训练自己。要时刻明确NULL的含义,每次你写SQL时,都要考虑:

    对于NULL来说谓词是否正确 NULL是否影响该函数的结果

    2.在Java内存中处理数据

    一些Java开发者十分了解SQL特性。偶尔JOIN,零散的UNION,没什么问题。但假如遇到视窗功能,结果集分组等情况又怎么样呢 很多Java开发人员会把SQL数据加载到内存,把数据转换成一些适合的集合类型,以十分冗长的循环结构在集合上执行恼人数学运算(至少在Java 8改进容器之前是这样的)。

    但一些SQL数据库除了支持SQL标准外,还支持先进的OLAP特性,执行效率更好,且更容易编写。一个非标准的例子就是甲骨文的MODEL子句。只是让数据库进行数据处理过程,将最终获取的结果加载到Java内存中。因为一些非常聪明的人已经优化了这些昂贵的产品。所以,事实上,通过向OLAP数据库上进行迁移,您将得到两个好处:

    简洁。它可能使得在SQL中编写正确代码会比在Java中相对容易 性能。该数据库将可能比你的算法要快。更重要的是,你不必再通过网络传输数百万条记录。

    解决办法

    每次你在Java中实现以数据为中心的算法时,要试着问问自己:有没有办法让数据库执行这些工作,而只把结果交付给我

    3.尽量使用UNION,而不是UNION ALL

    相对于UNION,UNION ALL需要额外的关键字显得相形见绌。假如在SQL标准已定义如下支持,那将会好很多:

    UNION(允许重复) UNION DISTINCT(去掉重复)

    一般很少需要去除重复(有时去重甚至是错误的),而且对于具有很多列的大结果集,它往往很慢,因为这两个子查询需要排序,每个元组都需要与随后的元组进行比较。

    需要注意的是,即使SQL标准指定了INTERSECTALL和EXCEPTALL,但几乎没有任何数据库实现这些用处不大的操作。

    解决办法

    你每次写到UNION时,要考虑下你是否实际上想写的是UNIONALL。

    4.使用JDBC分页功能将大量结果分页

    大多数数据库都支持通过LIMIT.. OFFSET,TOP .. START AT、OFFSET.. FETCH等子句以某种方式对结果进行分页。在没有对这些子句的支持下,但仍然有ROWNUM(Oracle)或ROW_NUMBER()OVER()(DB2,SQL Server 2008和更低版本),这比在内存中分页要快得多。而且这对于大数据集更是明显。

    解决办法

    只要使用那些子句或工具(如jOOQ),可以为你模拟上述分页子句。

    5.将Java内存中实现连接

    从SQL的发展的初期,一些开发商在面对SQL连接时仍然有一种不安的感觉。一直存在着一种固有的恐惧---JOIN速度缓慢。假如基于成本的优化器选择执行嵌套循环,创建一个连接表源之前,加载完整表到数据库内存,那速度确实十分缓慢。但很这少发生。通过适当的谓词,约束和索引,MERGEJOIN和 HASHJOIN操作是非常快的。这与正确的元数据相关(我不用再举Tom Kyte的例子了)。然而,也有仍然可能有不少Java开发人要会从单独的查询中加载两个表到map容器中,在java内存中以某种方式进行连接操作。

    解决办法

    假如你从多个步骤的多个表中进行了SELECT操作,那要慎重考虑一下是否可以在一条语句中表达你所需要的查询功能。

    6.使用DISTINCT或UNION从一个笛卡尔积中删除重复

    冗长连接的存在,会导致SQL语句中起作用的关系显得十分松散。具体地,假如涉及到多列外键关系,很有可能忘记在JOINON子句上添加谓词。这可能会导致重复的记录,但也许只在特殊情况下。然后一些开发者可能会选择使用DISTINCT再次删除这些重复记录。这种错误有三种危害:

    可能治标不治本。甚至在某些边缘情况下,标都治不了 这在有很多列的大结果集上会十分的缓慢。DISTINCT会执行ORDER BY操作来删除重复。 这在大型笛卡尔积中也十分的缓慢,因为这样做仍然会导致在内存中加载大量数据。

    解决办法

    作为一个经验法则,当你得到不想要的重复结果时,应该首先检查你的连接谓词。因为有可能是在某个地方存在着一个不易察觉的笛卡尔积。

    7.不使用MERGE语句

    严格意义上讲,这不是一个真正的错误,可能只是对于功能强大的MERGE语句缺乏足够的认知或存在着某种恐惧而已。有些数据库包括其他形式的UPSERT 语句,如MySQL的ONDUPLICATE KEY UPDATE子句。但MERGE真的十分强大,最重要的是在数据库中,它在很大程度上扩展了SQL标准,如SQL Server。

    解决办法

    假如你通过链接INSERT和UPDATE或链接SELECT... FOR UPDATE来实现UPSERTING,那么你要多想一想。抛开与运行条件的风险,你也许可以使用一个简单的MERGE语句来达到目的。

    8.使用了聚合函数,而不是窗体功能

    引入窗函数之前,使用GROUPBY子句与投影聚合函数是汇总数据的唯一方式。这在大部分情况下都十分有效,假如聚集后的数据需要由常规的数据进行补充,该分组的查询可以置于连接子查询中。

    但是,SQL:2003定义了窗口功能,目前很多主流的数据库厂商也纷纷实现了窗口功能。窗口功能可以聚集结果集中未被分组的数据。事实上,每个窗口的功能支持自身独立的PARTITIONBY子句,这对于报表类应用是一个非常有用的工具。

    使用窗口功能将:

    导致更多的可读性SQL(减少子查询中非专用GROUP BY子句的存在) 提高性能,作为一个RDBMS很可能更容易优化其窗口功能。

    解决办法

    当你在一个子查询写一个GROUPBY子句时,仔细想想这是否能用一个窗口函数来完成。

    9.使用内存排序法进行间接排序

    在SQLORDER BY子句支持多种类型的表达式,包括CASE语句,这对间接排序非常有用。你应该永远可能在Java内存中对数据进行排序,因为你认为:

    SQL排序太慢 SQL排序不能做到这一点

    解决办法

    假如你在内存中对任何SQL数据进行排序,请仔细想想,你是否能把排序迁移至数据库中。这和将分页迁移至数据库中的原因一样。

    10 一个接一个的插入大量的记录

    JDBC包含了批处理,而且你应该使用它。面对成千上万的记录,切勿为每一条记录都创建一个新的PreparedStatement来进行插入操作。假如你要将所有记录都插入到同一个表,使用单一的SQL语句和多个绑定值集合建立一个批处理的INSERT语句。根据您的数据库和数据库配置,您可能需要在一定数量的插入的记录后进行提交,为了保持UNDO日志不过分庞大。

    解决办法

    始终批量插入大型数据集。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    商业智能成CIO优先关注点 技术落地方显成效(1)

    用linux安装MySQL时产生问题破解

    JAVA中关于Map的九大问题

    windows 7旗舰版无法使用远程登录如何开启telnet服务

    Android View 事件分发机制详解

    MySQL用户变量的用法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。