【发布时间】:2021-03-05 02:03:50
【问题描述】:
PreparedStatement.executeQuery() 的执行时间比直接通过 shell 运行的时间长约 20 倍。我已经用计时器记录以确定这种方法是罪魁祸首。
查询和一些数据库信息(暂时忽略 Java 问题):
mysql> SELECT username from users where user_id = 1; // 闪电般的速度
通过 mysqlslap 运行相同的查询 1000 次也非常快。
mysqlslap --create-schema=mydb --user=root -p --query="select username from phpbb_users where user_id = 1" --number-of-queries=1000 --concurrency=1
Benchmark
Average number of seconds to run all queries: 0.051 seconds
Minimum number of seconds to run all queries: 0.051 seconds
Maximum number of seconds to run all queries: 0.051 seconds
Number of clients running queries: 1
Average number of queries per client: 1000
问题:在 JDBC 中执行相同的查询会显着降低速度。在 for 循环中调用下面的queryUsername() 1,000 次(这在 Main 方法中调用,此处未显示)大约需要 872 毫秒。慢了约 17 倍!我通过在不同的位置放置计时器来追踪大量使用(为了简洁省略了一些)。主要嫌疑人是stmt.executeQuery(),它占用了 872 毫秒运行时间中的 776 毫秒。
public static String queryUsername() {
String username = "";
// DBCore.getConnection() returns HikariDataSource.getConnection() implementation exactly as per https://www.baeldung.com/hikaricp
try (Connection connection = DBCore.getConnection();
PreparedStatement stmt = connection.prepareStatement("SELECT username from phpbb_users where user_id = ?");) {
stmt.setInt(1, 1); // just looking for user_id 1 for now
// Google timer used to measure how long executeQuery() is taking
// Another Timer is used outside of this method call to see how long
// total execution takes.
// Approximately 1 second in for loop calling this method 1000 times
Stopwatch s = Stopwatch.createStarted();
try (ResultSet rs = stmt.executeQuery();) {
s.stop(); // stopping the timer after executeQuery() has been called
timeElapsed += s.elapsed(TimeUnit.MICROSECONDS);
while (rs.next())
{
username = rs.getString("username"); // the query returns 1 record
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return username;
}
其他上下文和尝试的事情:
-
SHOW OPEN TABLES有几张表打开,但都有 In_use=0 和 Name_locked=0。 -
SHOW FULL PROCESSLIST看起来很健康。 - user_id 是索引主键
- 服务器是 Upcloud 每月 5 美元的 1 核、1GB RAM,运行 Ubuntu 20.04.1 LTS(GNU/Linux 5.4.0-66-generic x86_64)。 Mysql Ver 8.0.23-0ubuntu0.20.04.1 for Linux on x86_64 ((Ubuntu))
- JDBC Driver为mysql-connector-java_8.0.23.jar,通过https://dev.mysql.com/downloads/connector/j/从mysql-connector-java_8.0.23-1ubuntu20.04_all获取
【问题讨论】:
-
更新:几个月后...我能够通过将 JDBC 驱动程序更新为 mysql-connector-java-8.0.26.jar 将查询时间减少一半
-
更新:通过切换到 MariaDB Connector/J 2.7.4 kb.askmonty.org/en/about-the-mariadb-java-client,我能够实现更快的查询时间
标签: java mysql performance jdbc hikaricp