我将 mysql 与 JDBC 结合使用。
我有一个大型示例表,其中包含 630 万行,我正在尝试对其执行高效的选择查询。见下文:
像这样执行SELECT
查询SELECT latitude, longitude FROM 3dag WHERE
timestamp BETWEEN "+startTime+"AND "+endTime+"AND HourOfDay=4 AND DayOfWeek=3"
的运行时间非常高,达到 256356 毫秒,或略高于四分钟。我对同一查询的解释给出了我这个:
我检索数据的代码如下:
Connection con = null;
PreparedStatement pst = null;
Statement stmt = null;
ResultSet rs = null;
String url = "jdbc:mysql://xxx.xxx.xxx.xx:3306/testdb";
String user = "bigd";
String password = "XXXXX";
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url, user, password);
String query = "SELECT latitude, longitude FROM 3dag WHERE timestamp BETWEEN "+startTime+" AND "+endTime+" AND HourOfDay=4 AND DayOfWeek=3";
stmt = con.prepareStatement("SELECT latitude, longitude FROM 3dag WHERE timestamp>=" + startTime + " AND timestamp<=" + endTime);
stmt = con.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
rs = stmt.executeQuery(query);
System.out.println("Start");
while (rs.next()) {
int tempLong = (int) ((Double.parseDouble(rs.getString(2))) * 100000);
int x = (int) (maxLong * 100000) - tempLong;
int tempLat = (int) ((Double.parseDouble(rs.getString(1))) * 100000);
int y = (int) (maxLat * 100000) - tempLat;
if (!(y > matrix.length) || !(y < 0) || !(x > matrix[0].length) || !(x < 0)) {
matrix[y][x] += 1;
}
}
System.out.println("End");
JSONObject obj = convertToCRS(matrix);
return obj;
}catch (ClassNotFoundException ex){
Logger lgr = Logger.getLogger(Database.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
return null;
}
catch (SQLException ex) {
Logger lgr = Logger.getLogger(Database.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
return null;
} finally {
try {
if (rs != null) {
rs.close();
}
if (pst != null) {
pst.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Database.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
return null;
}
}
删除 while(rs.next())
循环中的每一行都会给我同样可怕的运行时间。
我的问题是如何优化此类查询?我很好奇 .setFetchSize()
以及这里的最佳值应该是多少。文档显示 INTEGER.MIN_VALUE 导致逐行获取,这是否正确?
感谢任何帮助。
编辑 在时间戳、DayOfWeek 和 HourOfDay 创建新索引后,我的查询运行速度加快了 1 分钟,并解释为:
最佳答案
预先的一些想法:
- 您是否确实检查了 SQL 执行时间(从 .executeQuery() 到第一行?)还是执行 + 迭代超过 630 万行?
- 您准备了 PreparedStatement 但不使用它?!
- 使用 PreparedStatement,将 tiemstamp、dayOfWeek、hourOfDay 作为参数传递
- 创建一个 可以满足您的where 条件的索引。以可以消除具有最高排名字段的最多项目的方式对键进行排序。
索引可能如下所示:
CREATE INDEX stackoverflow on 3dag(hourOfDay, dayOfWeek, Timestamp);
在 MySQL 中执行 SQL - 你什么时候到达那里?
- 尝试不使用
stmt.setFetchSize(Integer.MIN_VALUE);
这可能会产生许多不需要的网络往返。
关于java - 优化大表上的 MySQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34251541/