Spring jdbcTemplate 与 PreparedStatement。性能差异

mvb*_*b13 5 java sql spring

我正在使用 Oracle 11g。我的A,B,C数据库中有 3 个表()A <one-many> B <many-one> C 我有一段代码,它执行三个插入:首先是 inAC,然后是 in B。这段代码执行了很多次( 200000) 并200000在每个表中进行插入操作。

我有两种插入方式:

  1. jdbc 准备好的语句:

    DataSource ds = jdbcTemplate.getDataSource();
    
    try (Connection connection = ds.getConnection();
         PreparedStatement statement = connection.prepareStatement(sql1);
         PreparedStatement statement2 = connection.prepareStatement(sql2);
         PreparedStatement statement3 = connection.prepareStatement(sql3);) {
    
         connection.setAutoCommit(false);
         final int batchSize = 20;
         int count = 0;
    
         for (int i=1; i<= total; i++ ) {
    
             // Define sql parameters
    
             statement.setString(1, p1);
    
             statement2.setString(1, p2);
             statement2.setString(2, p3);
    
             statement3.setInt(1, p4);
             statement3.setString(2, p5);
    
             statement.addBatch();
             statement2.addBatch();
             statement3.addBatch();
    
             if (++count % batchSize == 0) {
                        statement.executeBatch();
                        statement.clearBatch();
                        statement2.executeBatch();
                        statement2.clearBatch();
                        statement3.executeBatch();
                        statement3.clearBatch();
                        connection.commit();
                        System.out.println(i);
             }
          }
    
          statement.executeBatch();
          statement.clearBatch();
          statement2.executeBatch();
          statement2.clearBatch();
          statement3.executeBatch();
          statement3.clearBatch();
          connection.commit();
       } 
       catch (SQLException e) {
           e.printStackTrace();
       }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 弹簧 jdbc 模板:

     List<String> bulkLoadRegistrationSql = new ArrayList<String>(20);
    
     for (int i=1; i<= total; i++ ) {
    
         // 1. Define sql parameters p1,p2,p,3p4,p5
    
         // 2. Prepare sql using parameters from 1
         String sql1String = ...
         String sql2String = ...
         String sql3String = ...
    
         bulkLoadRegistrationSql.add(sql1String);
         bulkLoadRegistrationSql.add(sql2String);
         bulkLoadRegistrationSql.add(sql3String);
    
         if (i % 20 == 0) {
              jdbcTemplate.batchUpdate(bulkLoadRegistrationSql
                  .toArray(new  String[bulkLoadRegistrationSql.size()]));
              //Clear inserted batch
              bulkLoadRegistrationSql = new ArrayList<String>(20);     
         }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)

我测量了执行时间total = 200000,结果对我来说非常混乱。spring jdbcTemplate1480秒执行,jdbc PreparedStatement200秒

我查看了jdbcTemplate源代码,发现它Statement在下面使用,效率应该低于PreparedStatement. 然而,结果差异太大,我不确定这是否仅仅因为 和 之间的差异Statement而发生PreparedStatement。你对此有何想法?如果jdbcTemplate替换为 ,理论上的结果应该相等namedParameterJdbcTemplate吗?

sch*_*ver 1

是的,它应该更接近,假设大部分时间都花在等待数据库的响应上。Spring 有其自身的开销,因此您将在客户端消耗更多的资源。

在使用占位符的预准备语句中,Oracle 仅解析一次 SQL,并生成一次计划。然后它会缓存解析结果以及 SQL 计划。在 JDBCTemplate 示例中,每个 SQL 语句对于解析器来说看起来都不同,因此需要服务器进行完整的解析和计划生成。根据 Oracle 服务器的性能,这将导致每个 SQL 语句的响应时间增加。对于 200,000 个 SQL 语句,净增加 1280 秒意味着每次调用额外花费 6.4 毫秒。对我来说,由于需要额外的解析,这似乎是一个合理的增长。

我建议在数据库调用中添加一些计时信息,以便您可以确认改进版本中的 SQL 响应时间较低。