我有以下代码执行查询并将其直接写入字符串缓冲区,然后将其转储到CSV文件中。我需要写大量的记录(最多一百万)。这适用于一百万条记录,对于一个大约200mb的文件大约需要半小时!在我看来好像很多时间,不确定这是否是最好的。即使它包括使用其他jar / db连接工具,也请向我推荐更好的方法。
....
eventNamePrepared = con.prepareStatement(gettingStats +
filterOptionsRowNum + filterOptions);
ResultSet rs = eventNamePrepared.executeQuery();
int i=0;
try{
......
FileWriter fstream = new FileWriter(realPath +
"performanceCollectorDumpAll.csv");
BufferedWriter out = new BufferedWriter(fstream);
StringBuffer partialCSV = new StringBuffer();
while (rs.next()) {
i++;
if (current_appl_id_col_display)
partialCSV.append(rs.getString("current_appl_id") + ",");
if (event_name_col_display)
partialCSV.append(rs.getString("event_name") + ",");
if (generic_method_name_col_display)
partialCSV.append(rs.getString("generic_method_name") + ",");
..... // 23 more columns to be copied same way to buffer
partialCSV.append(" \r\n");
// Writing to file after 10000 records to prevent partialCSV
// from going too big and consuming lots of memory
if (i % 10000 == 0){
out.append(partialCSV);
partialCSV = new StringBuffer();
}
}
con.close();
out.append(partialCSV);
out.close();
谢谢,
担
答案 0 :(得分:6)
只需直接写入BufferedWriter
,而不是构建StringBuffer
。
另请注意,您应该使用StringBuilder
代替StringBuffer
... StringBuffer
有内部锁定,这通常不是必需的。
答案 1 :(得分:5)
分析通常是了解为什么某些东西变慢的唯一确定方法。但是,在这个例子中,我会建议两件不为人知的事情:
答案 2 :(得分:3)
你可以调整各种各样的东西,但是为了真正的改进,我会尝试使用你用来生成文件的任何数据库的本机工具。如果它是SQL Server,这将是bcp,它可以获取查询字符串并直接生成文件。如果你需要从Java调用它,你可以将它作为一个进程生成。
作为一个例子,我刚刚运行了这个......
bcp“select * from trading..bar_db”queryout bar_db.txt -c -t,-Uuser -Ppassword -Sserver
...这会在10秒内生成一个包含200万行的170MB文件。
答案 3 :(得分:2)
我只是想为 Jared Oberhaus 的建议添加一个示例代码:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class CSVExport {
public static void main(String[] args) throws Exception {
String table = "CUSTOMER";
int batch = 100;
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@server:orcl", "user", "pass");
PreparedStatement pstmt = conn.prepareStatement(
"SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table);
ResultSet rs = pstmt.executeQuery();
rs.setFetchSize(batch);
ResultSetMetaData rsm = rs.getMetaData();
File output = new File("result.csv");
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(output), "UTF-8")), false);
Set<String> columns = new HashSet<String>(
Arrays.asList("COL1", "COL3", "COL5")
);
while (rs.next()) {
int k = 0;
for (int i = 1; i <= rsm.getColumnCount(); i++) {
if (columns.contains(rsm.getColumnName(i).toUpperCase())) {
if (k > 0) {
out.print(",");
}
String s = rs.getString(i);
out.print("\"");
out.print(s != null ? s.replaceAll("\"", "\\\"") : "");
out.print("\"");
k++;
}
}
out.println();
}
out.flush();
out.close();
rs.close();
pstmt.close();
conn.close();
}
}
答案 4 :(得分:0)
我有两个快速的想法。首先,你确定写入磁盘是问题吗?你真的可以花大部分时间等待来自数据库的数据吗?
第二种是尝试删除所有+“,”s,然后使用更多.adnds。它可能有助于考虑你做这些的频率。
答案 5 :(得分:0)
您提到您正在使用Oracle。您可能希望使用Oracle外部表功能或Oracle数据泵进行调查,具体取决于您要执行的操作。
请参阅http://www.orafaq.com/node/848(将数据卸载到外部文件中......)
另一个选项可能是通过sqlplus连接并在查询之前运行“spool”。
答案 6 :(得分:0)
写入缓冲的写入器通常很快“足够”。如果它不适合你,那么其他东西正在减慢它。
分析它的最简单方法是使用最新JDK中提供的jvisualvm。