java jdbc 执行sql语句批量操作问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java jdbc 执行sql语句批量操作问题相关的知识,希望对你有一定的参考价值。

我用java jdbc写的程序执行sql语句(mysql):insert into table_a (id,name,sex,email) select table_c.* from table_b,table_c where table_b.name = table_c.name;其中table_c的结构和table_a的结构一样,但是table_c中有800万条数据,sql执行后table_a中也得有十几万条数据,请问如何批量操作或者什么语句能提高执行效率?

sql优化:
1.name字段创建索引
2.“table_c.*” 不要用”*“号,可以换成table_c.id,table_c.name,table_c.sex,table_c.email
如果可以的话,你和以在insert into table_a 中间加 append ,这样写 insert /*+ append */ into
希望能帮到你!
参考技术A 你这样写已经不需要优化了。楼上说什么查出来放内存再插入都是在坑你,insert into xxx select xx from 这种sql在同一个数据库中速度最快了,数据库已经对它做了批量处理。 参考技术B prepareStatement 和Statement 的executeBatch 用了?追问

这个,我不知道怎么用prepareStatement的executeBatch,那个不是用来批量导入不同的sql语句的吗,我这就一个sql语句……

追答

你可以查一下JAVA JDBC批量操作的资料,看一下,希望对你有帮助

参考技术C 手动提交事物,大概100-500条 commit 一下追问

求大神给一小段代码,这是一个sql语句,从查询的结果中插入到另一张表,查询的时候应该很慢,如果是边查边插数据,我不会写啊,而且好像批处理不能插入select语句吧

追答

不是java吗 用java查出一部分数据放在内存,在插入呗,然后以此循环查询插入,还有你这SQL看着这么别扭呢,表结构一样还这样弄干嘛··,我知道了啊哎,才10几万条么,select table_c.* from table_b,table_c where table_b.name = table_c.name; 先查询这个,放java内存,然后执行插入insert into table_a (id,name,sex,email)这样不就快多了··

hibernate的update及JDBC数据库批量操作

最本质的区别是Session.update()更新的实体。而Query.update()更新的是执行SQL语句。
由此会带来一些问题。

性能问题

首先如果要使用Session去更新数据库需要执行一个获取实体的操作,也就是说需要先获取这个实体。而如果执行Query.update()则是直接执行SQL语句(或者HQL)。
本来以我的理解来看Query的效率应该比Session效率要高的,因为Query.update()更加原生,但是后来实现以下发现这个不一定。

首先,一般来说我们使用Query.update()不会直接构造一个Query区执行,因为软件中为了方便使用常常把Query.updata()包装成一些比较方便的方式,比如根据所给的class类型以及where的相关参数去生成Query所以这样更方便使用,这个过程也很麻烦。所以Query为了方便使用,效率有一定损失。比如我实测这两个方法使用相同的策略。但是使用生成Query形式的方式,10000次操作下Query.update()需要2min14s,而Session.update()则只需要使用1min19s。

批量操作

然后我又查了一下hibernate的批量操作的问题。
主要参考了这篇文章
Hiberante批量更新缺点及解决方案
Hibernate批量操作技巧

第一篇文章主要的观点在于两点:

以上批量更新方式有两个缺点:
(1)占用大量内存,必须把1万个Customer对象先加载到内存,然后一一更新它们。
(2)执行的update语句的数目太多,每个update语句只能更新一个Customer对象,必须通过1万条update语句才能更新一万个Customer对象,频繁的访问数据库,会大大降低应用的性能。

第一个缺点的可以通过session的flush和evict来尽可能提早释放Customer。
第二个缺点没有办法解决,作者推荐直接使用JDBC API来实现。或者使用储存过程来做实现更快。

第二篇文章主要在讨论如何在hibernate来尽可能实现快速批量操作

主要通过flush和设置batch_size来实现。

Statement、preparedStatement和CallableStatement的区别
主要参考了这两篇文章:

Statement、preparedStatement和CallableStatement的区别
主要观点:

Statement 每次执行sql语句,数据库都要执行sql语句的编译 ,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement.

PreparedStatement是预编译的,使用PreparedStatement有几个好处
a. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
b. 安全性好,有效防止Sql注入等问题。
c. 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;
d. 代码的可读性和可维护性。

CallableStatement接口扩展 PreparedStatement,用来调用存储过程,它提供了对输出和输入/输出参数的支持。CallableStatement 接口还具有对 PreparedStatement 接口提供的输入参数的支持。

但是按照目前的资料来看我对PreparedStatement和CallableStatement之间有什么区别。大概可以总结如下:

  • 首先CallableStatement是继承自PreparedStatement的。
  • PreparedStatement主要来数据库支持预编译就可以了,而CallableStatement则需要数据库支持存储过程才行。
  • 从执行效率来说CallableStatement要比PreparedStatement效率要高。
  • 对于PreparedStatement只要在编程语言中定义就好了,而对于CallableStatement还需要在编程语言中预先写好存储过程才行。

另外一些疑问:

  • 有一些说法是PreparedStatement就是存储过程,但是个人来说不太支持这种说法。我猜想可能是早起JDBC和存储过程版本支持问题。个人还是觉得CallableStatement的实现。
  • 另外一个问题就是PreparedStatement的预处理过程是经过缓存的。这里的缓存策略是一个问题,比如缓存何时刷新,是由数据库刷新还是可以程序控制之类的。目前还没有找到资料。

以上是关于java jdbc 执行sql语句批量操作问题的主要内容,如果未能解决你的问题,请参考以下文章

jdbc批量执行SQL insert 操作

java语句 sql 批量增加数据

hibernate的update及JDBC数据库批量操作

hibernate的update及JDBC数据库批量操作

mybatis批量操作

MyBatis批量增删改的另外一种思路(推荐)