[英]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,C
) A <one-many> B <many-one> C
我有一段代码,它执行三个插入:首先是A
和C
,之后是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: 我有两种方法可以插入:
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(); } }
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
. 但是结果的差异太大了,我不确定是否因为
Statement
和PreparedStatement
之间的区别而发生这种情况。 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.