在java中提高将查询结果写入CSV的性能
我有以下代码来执行查询并将其直接写入字符串缓冲区,然后将其转储到CSV文件。我需要写大量的记录(最多一百万条)。这适用于一百万条记录—大约200mb的文件大约需要半个小时!在我看来,这似乎是很多时间,不确定这是否是最好的。请向我推荐更好的方法,即使它包括使用其他JAR/db连接UTIL在java中提高将查询结果写入CSV的性能,java,performance,Java,Performance,我有以下代码来执行查询并将其直接写入字符串缓冲区,然后将其转储到CSV文件。我需要写大量的记录(最多一百万条)。这适用于一百万条记录—大约200mb的文件大约需要半个小时!在我看来,这似乎是很多时间,不确定这是否是最好的。请向我推荐更好的方法,即使它包括使用其他JAR/db连接UTIL .... eventNamePrepared = con.prepareStatement(gettingStats + filterOptionsRowNum + filterOptions); Re
....
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();
谢谢
Tam分析通常是了解事物为何缓慢的唯一可靠方法。然而,在这个例子中,我建议两件事是低挂果实:
分析通常是唯一确定事情进展缓慢的方法。然而,在这个例子中,我建议两件事是低挂果实:
直接写入
BufferedWriter
,而不是构建StringBuffer
还要注意,您可能应该使用
StringBuilder
而不是StringBuffer
StringBuffer
有一个内部锁,这通常是不必要的。直接写入BufferedWriter
,而不是构造StringBuffer
还要注意,您可能应该使用
StringBuilder
而不是StringBuffer
StringBuffer
有一个内部锁,这通常是不必要的。我有两个快速的想法。首先,您确定写入磁盘是问题所在吗?你真的会把大部分时间花在等待数据库的数据上吗
第二种方法是尝试删除所有的+“,”并使用更多的.appends。这可能有助于考虑你多久做一次这些事。我有两个快速的想法。首先,您确定写入磁盘是问题所在吗?你真的会把大部分时间花在等待数据库的数据上吗
第二种方法是尝试删除所有的+“,”并使用更多的.appends。这可能有助于考虑您执行这些操作的频率。您可以调整各种事情,但为了实现真正的改进,我将尝试使用您正在使用的任何数据库的本机工具来生成文件。如果是SQL Server,这将是bcp,它可以获取查询字符串并直接生成文件。如果需要从Java调用它,可以将其作为一个进程生成 作为一个例子,我刚刚运行了这个 bcp“select*from trading..bar_db”查询bar_db.txt-c-t,-Uuser-Ppassword-Sserver
…这在10秒内生成了一个170MB的文件,其中包含200万行。您可以对各种内容进行调整,但为了实现真正的改进,我将尝试使用您正在使用的任何数据库的本机工具来生成该文件。如果是SQL Server,这将是bcp,它可以获取查询字符串并直接生成文件。如果需要从Java调用它,可以将其作为一个进程生成 作为一个例子,我刚刚运行了这个 bcp“select*from trading..bar_db”查询bar_db.txt-c-t,-Uuser-Ppassword-Sserver
…这将在10秒内生成一个170MB的文件,其中包含200万行。您提到您正在使用Oracle。您可能希望研究使用Oracle外部表功能或Oracle数据泵,具体取决于您正在尝试执行的操作 请参阅(将数据卸载到外部文件…)
另一个选项是通过sqlplus连接并在查询之前运行“spool”。您提到您正在使用Oracle。您可能希望研究使用Oracle外部表功能或Oracle数据泵,具体取决于您正在尝试执行的操作 请参阅(将数据卸载到外部文件…)
另一个选项是通过sqlplus连接并在查询之前运行“spool”。我只是想为Jared Oberhaus的建议添加一个示例代码:
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.FileOutputStream;
导入java.io.OutputStreamWriter;
导入java.io.PrintWriter;
导入java.sql.Connection;
导入java.sql.DriverManager;
导入java.sql.PreparedStatement;
导入java.sql.ResultSet;
导入java.sql.ResultSetMetaData;
导入java.util.array;
导入java.util.HashSet;
导入java.util.Set;
公共类CSVExport{
公共静态void main(字符串[]args)引发异常{
String table=“客户”;
整批=100;
类forName(“oracle.jdbc.driver.OracleDriver”);
连接连接=DriverManager.getConnection(
“jdbc:oracle:thin:@server:orcl”,“user”,“pass”);
PreparedStatement pstmt=conn.prepareStatement(
“从“+表格”中选择/*+第一行(“+批次+”*/”);
结果集rs=pstmt.executeQuery();
rs.setFetchSize(批量);
ResultSetMetaData rsm=rs.getMetaData();
文件输出=新文件(“result.csv”);
PrintWriter out=新的PrintWriter(新的BufferedWriter(
新的OutputStreamWriter(
新文件输出流(输出),“UTF-8”)、假);
Set columns=newhashset(
数组.asList(“COL1”、“COL3”、“COL5”)
);
while(rs.next()){
int k=0;
对于(int i=1;i 0){
输出。打印(“,”);
}
字符串s=rs.getString(i);
输出。打印(“\”);
out.print(s!=null?s.replaceAll(“\”,“\\\”):”);
输出。打印(“\”);
k++;
}
}
out.println();
}
out.flush();
out.close();
克洛斯
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();
}
}