BufferedWriter 性能缓慢
Slow BufferedWriter Performance
我有一种方法可以将 44 MB 的数据从 ResultSet 写入 CSV 文件。但是,大约需要 3.5 分钟才能完成。对于只有 44 MB 的数据,这似乎很慢。任何人都可以看到任何减慢我的代码的东西吗?:
public static void convertToCSV(final ResultSet rs) throws SQLException, IOException {
final BufferedWriter fw = new BufferedWriter(new FileWriter(new File("alert.csv")));
while (rs.next()) {
fw.write(rs.getString("FIELD1")+",");
fw.write(rs.getString("FIELD2")+",");
fw.write(rs.getString("FIELD3")+",");
final String clobValue = rs.getString("FIELD4");
if(clobValue==null)
fw.write("null,");
else{
fw.write("\""+clobValue+"\",");
}
final Date date = new Date(rs.getLong("FIELD5"));
final DateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
final String dateTime[] = format.format(date).split(" ");
fw.write(dateTime[0]+",");
fw.write(dateTime[1]);
fw.write("\n");
}
fw.close();
}
这可能取决于 JDBC 驱动程序、您的提取策略、磁盘...
但是你当然可以避免创建这么多临时对象:
- 将
DateFormat
移出循环。
- 避免创建临时字符串
rs.getString("FIELD1")+","
而是对编写器执行两次写入调用。
- 避免拆分操作。
下面应该会快一点
fw.write(rs.getString("FIELD1"));
fw.write(',');
还在循环之前声明和准备 SimpleDateFormat。
final DateFormat format = new SimpleDateFormat("yyyyMMdd','HH:mm:ss");
(此处不需要单引号。)
没有 split
这很昂贵。
这样的事情可能会更快
public static void convertToCSV(final ResultSet rs) throws SQLException, IOException {
final BufferedWriter fw = new BufferedWriter(new FileWriter(new File("alert.csv")));
final DateFormat format = new SimpleDateFormat("'yyyyMMdd','HH:mm:ss'");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
while (rs.next()) {
StringBuilder sb = new StringBuilder();
sb.append(rs.getString("FIELD1")).append(',')
.append(rs.getString("FIELD2")).append(',')
.append(rs.getString("FIELD3")).append(',');
final String clobValue = rs.getString("FIELD4");
if(clobValue==null)
sb.append("null,");
else{
sb.append('\"').append(clobValue).append('\"').append(',');
}
Date date = new Date(rs.getLong("FIELD5"));
sb.append(format.format(date)).append('\n');
fw.write(sb.toString());
}
fw.close();
}
DateFormat
的创建只在循环外完成一次。
- 使用
StringBuilder
- 尽可能避免创建临时对象。
您甚至可以重用 StringBuilder
,方法是将创建的内容移出循环并在编写后执行 setLength(0)
。
您可以增加生成 ResultSet
的 Statement
的提取大小 - 这将减少返回数据库以提取下一批行所需的次数(默认设置为 10)。这样做的缺点是它会增加 ResultSet
的内存占用,因为它将在内存中保存更多数据。
您的 SimpleDatFormat
对象是在循环的每次迭代中使用相同的数据创建的 - 如果您将它移到循环之外,您只会实例化它一次。您也可以将 setTimeZone(...)
语句移到循环外。
String
每次使用变量值进行串联都会在内部创建一个新的 StringBuilder
对象 - 您可以通过确保从不在循环中进行串联来获得更多收益。您可以通过手动创建自己的 StringBuilder
来完成此操作,将整行的数据放入其中,然后将行写入 BufferedWriter
一次(可能会占用更多内存)或者您可以进行更多 write(...)
调用以避免进行连接。
我有一种方法可以将 44 MB 的数据从 ResultSet 写入 CSV 文件。但是,大约需要 3.5 分钟才能完成。对于只有 44 MB 的数据,这似乎很慢。任何人都可以看到任何减慢我的代码的东西吗?:
public static void convertToCSV(final ResultSet rs) throws SQLException, IOException {
final BufferedWriter fw = new BufferedWriter(new FileWriter(new File("alert.csv")));
while (rs.next()) {
fw.write(rs.getString("FIELD1")+",");
fw.write(rs.getString("FIELD2")+",");
fw.write(rs.getString("FIELD3")+",");
final String clobValue = rs.getString("FIELD4");
if(clobValue==null)
fw.write("null,");
else{
fw.write("\""+clobValue+"\",");
}
final Date date = new Date(rs.getLong("FIELD5"));
final DateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
final String dateTime[] = format.format(date).split(" ");
fw.write(dateTime[0]+",");
fw.write(dateTime[1]);
fw.write("\n");
}
fw.close();
}
这可能取决于 JDBC 驱动程序、您的提取策略、磁盘...
但是你当然可以避免创建这么多临时对象:
- 将
DateFormat
移出循环。 - 避免创建临时字符串
rs.getString("FIELD1")+","
而是对编写器执行两次写入调用。 - 避免拆分操作。
下面应该会快一点
fw.write(rs.getString("FIELD1"));
fw.write(',');
还在循环之前声明和准备 SimpleDateFormat。
final DateFormat format = new SimpleDateFormat("yyyyMMdd','HH:mm:ss");
(此处不需要单引号。)
没有 split
这很昂贵。
这样的事情可能会更快
public static void convertToCSV(final ResultSet rs) throws SQLException, IOException {
final BufferedWriter fw = new BufferedWriter(new FileWriter(new File("alert.csv")));
final DateFormat format = new SimpleDateFormat("'yyyyMMdd','HH:mm:ss'");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
while (rs.next()) {
StringBuilder sb = new StringBuilder();
sb.append(rs.getString("FIELD1")).append(',')
.append(rs.getString("FIELD2")).append(',')
.append(rs.getString("FIELD3")).append(',');
final String clobValue = rs.getString("FIELD4");
if(clobValue==null)
sb.append("null,");
else{
sb.append('\"').append(clobValue).append('\"').append(',');
}
Date date = new Date(rs.getLong("FIELD5"));
sb.append(format.format(date)).append('\n');
fw.write(sb.toString());
}
fw.close();
}
DateFormat
的创建只在循环外完成一次。- 使用
StringBuilder
- 尽可能避免创建临时对象。
您甚至可以重用 StringBuilder
,方法是将创建的内容移出循环并在编写后执行 setLength(0)
。
您可以增加生成 ResultSet
的 Statement
的提取大小 - 这将减少返回数据库以提取下一批行所需的次数(默认设置为 10)。这样做的缺点是它会增加 ResultSet
的内存占用,因为它将在内存中保存更多数据。
您的 SimpleDatFormat
对象是在循环的每次迭代中使用相同的数据创建的 - 如果您将它移到循环之外,您只会实例化它一次。您也可以将 setTimeZone(...)
语句移到循环外。
String
每次使用变量值进行串联都会在内部创建一个新的 StringBuilder
对象 - 您可以通过确保从不在循环中进行串联来获得更多收益。您可以通过手动创建自己的 StringBuilder
来完成此操作,将整行的数据放入其中,然后将行写入 BufferedWriter
一次(可能会占用更多内存)或者您可以进行更多 write(...)
调用以避免进行连接。