简体   繁体   English

Spring jdbcTemplate与PreparedStatement。 性能差异

[英]Spring jdbcTemplate vs PreparedStatement. Performance difference

I am using Oracle 11g. 我正在使用Oracle 11g。 I have 3 tables( A,B,C ) in my database A <one-many> B <many-one> C I have a piece of code, that performs three inserts: firstly in A and C , after that in B . 我的数据库中有3个表( A,B,CA <one-many> B <many-one> C我有一段代码,它执行三个插入:首先是AC ,之后是B This piece of code is executed a lot of times( 200000 ) and makes 200000 insert operations in each table. 这段代码执行了很多次( 200000 )并在每个表中进行了200000插入操作。

I have two ways to make an insertion: 我有两种方法可以插入:

  1. jdbc PreparedStatement: jdbc PreparedStatement:

     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(); } } 
  2. Spring jdbcTemplate: Spring jdbcTemplate:

      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); } } 

I measured execution time for total = 200000 and results are very confusing for me. 我测量了total = 200000执行时间,结果对我来说非常混乱。 Spring jdbcTemplate is executed in 1480 seconds, jdbc PreparedStatement in 200 seconds Spring jdbcTemplate在1480秒内执行,jdbc PreparedStatement在200秒内执行

I looked into jdbcTemplate source and found, that it uses Statement underneath, which should be less efficient than PreparedStatement . 我查看了jdbcTemplate源代码,发现它在下面使用了Statement ,它应该比PreparedStatement效率低。 However the difference in results is too big and I am not sure if this happens just because of the difference between Statement and PreparedStatement . 但是结果的差异太大了,我不确定是否因为StatementPreparedStatement之间的区别而发生这种情况。 What are your ideas on that? 你有什么想法? Should the results theoretically be equaled if jdbcTemplate is replaced on namedParameterJdbcTemplate ? 如果在jdbcTemplate上替换namedParameterJdbcTemplate理论上结果是否相等?

Yes it should be much closer, assuming the majority of the time was spent waiting for the responses from the database. 是的,它应该更接近,假设大部分时间都花在等待数据库的响应上。 Spring has its own overhead so you will have some more resource consumption on the client side. Spring有自己的开销,所以你会在客户端有更多的资源消耗。

In a prepared statement using placeholders, Oracle only parses the SQL once, and generates the plan once. 在使用占位符的预准备语句中,Oracle仅解析SQL一次,并生成一次计划。 It then caches the parse results, along with the plan for the SQL. 然后它会缓存解析结果以及SQL的计划。 In your JDBCTemplate example, each SQL statement looks different to the parser and will therefore require a full parse and plan generation by the server. 在JDBCTemplate示例中,每个SQL语句看起来与解析器不同,因此需要服务器进行完整的解析和计划生成。 Depending on your Oracle server's horsepower, this will result in an increased response time for each SQL statement. 根据您的Oracle服务器的功能,这将导致每个SQL语句的响应时间增加。 For 200,000 SQL statements, a net increase of 1280 seconds translates into an additional 6.4 milliseconds per call. 对于200,000个SQL语句,净增加1280秒转换为每次调用额外6.4毫秒。 That, to me, seems like a reasonable increase due to the additional parsing required. 对我来说,由于需要额外的解析,这似乎是合理的增加。

I suggest adding some timing information to the database calls, so you can confirm that the SQL response time is lower in the improved version. 我建议在数据库调用中添加一些计时信息,以便确认改进版本中的SQL响应时间较短。

Spring JDBCTemplate also has methods that use prepared Statement. Spring JDBCTemplate也有使用预处理Statement的方法。 Please Refer this link Your test results make sense - you cannot compare execution using prepared statement and Ordinary SQL. 请参考此链接您的测试结果是有意义的 - 您无法比较使用预准备语句和普通SQL的执行。

There are overloaded batchUpdate methods in Spring JDBCTemplate that uses Prepared statements for example the below function. Spring JDBCTemplate中有重载的batchUpdate方法,它使用Prepared语句,例如下面的函数。

int[][] batchUpdate(String sql, final Collection batchArgs, final int batchSize, final ParameterizedPreparedStatementSetter pss) int [] [] batchUpdate(String sql,final Collection batchArgs,final int batchSize,final ParameterizedPreparedStatementSetter pss)

For any given SQL, 50 to 80 percent of a database engine's time is spent computing access paths. 对于任何给定的SQL,数据库引擎的50%到80%的时间用于计算访问路径。

When you use PreparedStatement directly, the database engine computes the access path once and returns a handle to the already computed access path (in the "prepare" phase). 直接使用PreparedStatement时,数据库引擎会计算一次访问路径,并返回已计算的访问路径的句柄(在“准备”阶段)。 When the prepared statement is invoked, the database engine only has to apply the parameters to the already prepared access path and return the cursor. 调用预准备语句时,数据库引擎只需将参数应用于已准备好的访问路径并返回游标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM