从网上了解到的资料,PrepareStatement默认情况下是没有开启JDBC的预编译功能的,也没有开启mysql的预编译功能 。
也就是说,在性能上,与传统的statement没什么差别。
这简直是颠覆了我的认知,我以为PrepareStatement是开启了预编译的,性能会有所提升,就来进行测试,看看prepareStatement对性能到底有没有提升。
测试环境Mysql8.0,JDBC驱动8.0
@Test
public void t() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dianping?serverTimezone=Asia/Shanghai", "root", "1234");
String sql = "select * from t where id = 1;";
Statement statement = connection.createStatement();
PreparedStatement preparedStatement = connection.prepareStatement(sql);
Instant start = Instant.now();
for(int i=0;i<10000;i++){
preparedStatement.executeQuery();
}
Instant end = Instant.now();
preparedStatement.close();
System.out.println("花费时间:"+Duration.between(start, end).toMillis());
start = Instant.now();
for(int i=0;i<10000;i++){
statement.executeQuery(sql);
}
end = Instant.now();
System.out.println("花费时间:"+Duration.between(start, end).toMillis());
statement.close();
connection.close();
}
执行多次的测试结果,发现预编译居然要慢一些???
花费时间:1770
花费时间:1541
花费时间:2039
花费时间:1798
花费时间:1948
花费时间:1674
花费时间:1827
花费时间:1585
不行,换个方式测试一下,我们把statement放在前面执行,看看有什么不同的结果。
仅仅交换了两个for循环的位置
@Test
public void t() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dianping?serverTimezone=Asia/Shanghai", "root", "1234");
String sql = "select * from t where id = 1;";
Statement statement = connection.createStatement();
PreparedStatement preparedStatement = connection.prepareStatement(sql);
Instant start = Instant.now();
for(int i=0;i<10000;i++){
statement.executeQuery(sql);
}
Instant end = Instant.now();
System.out.println("花费时间:"+Duration.between(start, end).toMillis());
statement.close();
start = Instant.now();
for(int i=0;i<10000;i++){
preparedStatement.executeQuery();
}
end = Instant.now();
System.out.println("花费时间:"+Duration.between(start, end).toMillis());
preparedStatement.close();
connection.close();
}
结果
花费时间:1812
花费时间:1566
花费时间:1815
花费时间:1537
花费时间:1878
花费时间:1633
花费时间:1877
花费时间:1620
这是什么情况?居然是先后顺序影响的查询结果,难道是mysql内部进行了优化?
希望有大佬能帮忙分析一下怎么回事。
不行还要再换一种方式,测试还是要进行下去的。
@Test
public void t1() throws SQLException {
String sql = "select * from t where id = 1;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
Instant start = Instant.now();
for(int i=0;i<100000;i++){
preparedStatement.executeQuery();
}
Instant end = Instant.now();
System.out.println("花费时间:"+Duration.between(start, end).toMillis());
preparedStatement.close();
connection.close();
}
@Test
public void t2() throws SQLException {
String sql = "select * from t where id = 1;";
Statement statement = connection.createStatement();
Instant start = Instant.now();
for(int i=0;i<100000;i++){
statement.executeQuery(sql);
}
Instant end = Instant.now();
System.out.println("花费时间:"+Duration.between(start, end).toMillis());
statement.close();
connection.close();
}
把两个测试分开,为了能更清楚的显示出差距,查询次数修改为100000。
这下结果就正确了,两个程序执行查询,结果都差不多,甚至在某些时候,非预编译的还要比与编译的快一点(猜想可能是防止注入影响的,只是猜想),预编译的那个比起非预编译的的确是没有效率的提升。可以尝试将查询次数修改的更大,看看到底谁更快。
两段测试经过多次的测试,结果都是在15s到16s的样子。由此可见,JDBC预编译在默认情况下,比起非预编译确实是没什么提升。
关于mysql的与预编译,详情可以参考下面两个文章