我的任务是从 SQL Server 数据库中读取 15+ 百万条记录,对它们执行一些处理,并将结果写入平面文件。
如何使用 Java 有效地做到这一点?
我最初的想法是在查询执行时以块的形式查询数据或将结果流回处理(如果可能的话)。
我的任务是从 SQL Server 数据库中读取 15+ 百万条记录,对它们执行一些处理,并将结果写入平面文件。
如何使用 Java 有效地做到这一点?
我最初的想法是在查询执行时以块的形式查询数据或将结果流回处理(如果可能的话)。
看起来 sql-server 的 jdbc 驱动程序尊重 fetchsize 提示(它建议一次读取多少行),因此您应该能够发出一个查询并遍历您的结果集,处理并将行写入文件你走。例如:
public static void toFlat(Connection conn, File file, String destcode) {
PreparedStatement ps = null;
ResultSet rs = null;
BufferedWriter out = null;
try {
ps = conn.prepareStatement(
// col#: 1 2 3 4
"SELECT threatid, lastname, firstname, flightnum " +
"FROM travel.passengers " +
"JOIN threats.aliases USING (firstname, lastname) " +
"WHERE destination = ?" // param# 1
);
ps.setString(1,destcode); // param# 1
out = new BufferedWriter(new FileWriter(file));
// provides hint for driver to load x rows at a time:
ps.setFetchSize(1000);
ps.executeQuery();
rs = ps.getResultSet();
while(rs.next()) {
Integer threatid = rs.getInt(1);
String lastname = rs.getString(2);
String firstname = rs.getString(3);
Integer flightnum = rs.getInt(4);
//rubber meets road:
String row = processRow(threatid, lastname, firstname, flightnum);
out.write(row);
}
} catch(SQLException e) {
// TODO
} catch (IOException e) {
// TODO
e.printStackTrace();
} finally {
try {
ps.close();
} catch(Exception e){
//TODO
}
try {
rs.close();
} catch(Exception e){
//TODO
}
try {
out.close();
} catch(Exception e){
//TODO
}
}
}
如果效率仅与阅读有关,那么有关fetch size的答案就是要走的路。如果您在数据库主机上运行 Java 程序(=> localhost 连接),它会给您带来性能提升。
如果有效地应用于处理,请尽可能多地在 SQL 查询中执行。我们进行了测量,RDBMS 的性能优于 Java。例如,在 Java 中过滤和排序需要更长的时间。再次用 Java 重新实现数据库功能是没有意义的,而且速度更慢。
如果您的算法使用 SQL 查询不容易实现,请在存储过程中进行额外(过程)处理,将其完全编写为存储过程或在 SQL 查询中使用存储函数。将存储函数与 SQL 查询结合使用是一种非常强大且快速的组合。您的 Java 客户端只是读取结果,然后将它们直接写入磁盘。没有缓冲,没有处理,只有 I/O。
如果您使用的是 Oracle、PostgreSql 或 DB2,您甚至可以用 Java 编写存储过程/函数。