关闭 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日志不过分庞大。

    解决办法

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

    上一篇返回首页 下一篇

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

    别人在看

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    Cornell大神Kleinberg的经典教材《算法设计》是最好入门的算法教材

    从 Microsoft 下载中心安装 Windows 7 SP1 和 Windows Server 2008 R2 SP1 之前要执行的步骤

    Llama 2基于UCloud UK8S的创新应用

    火山引擎DataTester:如何使用A/B测试优化全域营销效果

    腾讯云、移动云继阿里云降价后宣布大幅度降价

    字节跳动数据平台论文被ICDE2023国际顶会收录,将通过火山引擎开放相关成果

    这个话题被围观超10000次,火山引擎VeDI如此解答

    误删库怎么办?火山引擎DataLeap“3招”守护数据安全

    IT头条

    平替CUDA!摩尔线程发布MUSA 4性能分析工具

    00:43

    三起案件揭开侵犯个人信息犯罪的黑灰产业链

    13:59

    百度三年开放2.1万实习岗,全力培育AI领域未来领袖

    00:36

    工信部:一季度,电信业务总量同比增长7.7%,业务收入累计完成4469亿元

    23:42

    Gartner:2024年全球半导体营收6559亿美元,AI助力英伟达首登榜首

    18:04

    技术热点

    iOS 8 中如何集成 Touch ID 功能

    windows7系统中鼠标滑轮键(中键)的快捷应用

    MySQL数据库的23个特别注意的安全事项

    Kruskal 最小生成树算法

    Ubuntu 14.10上安装新的字体图文教程

    Ubuntu14更新后无法进入系统卡在光标界面解怎么办?

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

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