mysql/oracle jdbc大数据量插入优化

10.10.6  大数据量插入优化

在很多涉及支付和金融相关的系统中,夜间会进行批处理,在批处理的一开始或最后一般需要将数据回库,因为应用和数据库通常部署在不同的服务器,而且应用所在的服务器一般也不会去安装oracle客户端,同时为了应用管理和开发模式统一,很多会利用mybatis的foreach collection特性,如下:

<insert id="batchInsertStudent" parameterType="List">

         insert into /*+ append_values */ t_student(id,name)

<foreach collection="list" item="item" index="index" separator="union all">

                  select #{item.id}, #{item.name} from dual

         </foreach>

</insert>

还有一些开发人员会仿照mysql的写法,拼接成一个巨大的SQL,一次性提交给oracle执行,如下:

 

 

这些写法会生成很长的SQL语句,严重浪费客户端内存和oracle服务器共享池,如果这段期间需要生成AWR报告的话,没有这些语句几十秒就完成了,有这些语句的时候可能要十几分钟,生成的AWR文件就有十几兆,并且oracle服务器CPU利用率一直高负载。如果仅仅是如此也就罢了,最主要是这些看似优化的方法实际上性能仅仅比一条条提交提升快了几倍而已,对于一次性加载几十万、几百万行来说,并没有采用真正高效的做法。对于此类需要加载大量数据的方法,如本书第7章所述,应尽可能采用特殊优化的接口而不是为通用CRUD目的实现的接口,比如mybatis提供了批量执行器ExecutorType.BATCH,JDBC也提供了标准的批处理接口。

mybatis批量执行器的实现如下:

    <insert id="insertBatch" parameterType="chapter10.batch.pojo.User">

        insert into EMP (EMPNO,ENAME,JOB,MGR,SAL,COMM,DEPTNO)

        values (#{empno,jdbcType=BIGINT},……,#{deptno,jdbcType=BIGINT})

    </insert>

                   SqlSession session2 = sqlMapper.openSession(ExecutorType.BATCH, false);// 批处理方式 手动提交事务

                   UserMapper userDao2 = session2.getMapper(UserMapper.class);

                   try {

                            long t1 = System.currentTimeMillis();

                            for (int i = 0; i < 1000000; i++) {

                                     User user_new = new User();

                                     user_new.setComm(i % 10000);

                                     ……

                                     user_new.setSal(i % 1000);

                                     userDao2.insertBatch(user_new);

                                      if (i % 10000 == 0) {

                                               session2.commit();

                                     }

                            }

                            System.out.println(System.currentTimeMillis() - t1 + "ms");

                   } finally {

                            session2.commit();

                            session2.close();

                   }

oracle jdbc批处理的实现如下:

                   Connection connection = dbpool.getConnection();

                   connection.setAutoCommit(false);

                   PreparedStatement preparedStatement = connection.prepareStatement("insert into EMP (EMPNO,ENAME,JOB,MGR,SAL,COMM,DEPTNO) values (?,?,?,?,?,?,?)");

                   long t1 = System.currentTimeMillis();

                   for (int i = 0; i < 1000000; i++) {

                            User user_new = new User();

                            user_new.setComm(i % 10000);

                            ……

preparedStatement.setInt(7, user_new.getDeptno());

                            preparedStatement.addBatch();

                            if (i % 10000 == 0) {

                                     preparedStatement.executeBatch();

                                     connection.commit();

                            }

                   }

                   preparedStatement.close();

加载100w数据,使用jdbc Batch需要3秒左右,mybatis batch(标准JDBC批处理)9.2秒,mybatis foreach每5000条(1w时报java.sql.SQLException: ORA-01745: 无效的主机/绑定变量名)提交一次,需要执行203秒左右,甚至不如每行一次、每10000行提交一次的效率,并且子游标的共享内存占用了27M,固定内存加起来占了14M左右,如下:

SQL> select o.sql_id, sharable_mem, persistent_mem, runtime_mem

  2    from v$sql o

  3   where o.sql_text like '%insert into EMP (%'

  4     and sql_text not like '%v$sql%'

  5  ;

SQL_ID        SHARABLE_MEM PERSISTENT_MEM RUNTIME_MEM

------------- ------------ -------------- -----------

bqwhad7f0gxxd     27473066        9127256     4925984

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值