在java中提高将查询结果写入CSV的性能

在java中提高将查询结果写入CSV的性能,java,performance,Java,Performance,我有以下代码来执行查询并将其直接写入字符串缓冲区,然后将其转储到CSV文件。我需要写大量的记录(最多一百万条)。这适用于一百万条记录—大约200mb的文件大约需要半个小时!在我看来,这似乎是很多时间,不确定这是否是最好的。请向我推荐更好的方法,即使它包括使用其他JAR/db连接UTIL .... eventNamePrepared = con.prepareStatement(gettingStats + filterOptionsRowNum + filterOptions); Re

我有以下代码来执行查询并将其直接写入字符串缓冲区,然后将其转储到CSV文件。我需要写大量的记录(最多一百万条)。这适用于一百万条记录—大约200mb的文件大约需要半个小时!在我看来,这似乎是很多时间,不确定这是否是最好的。请向我推荐更好的方法,即使它包括使用其他JAR/db连接UTIL

....
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

分析通常是了解事物为何缓慢的唯一可靠方法。然而,在这个例子中,我建议两件事是低挂果实:

  • 直接写入缓冲写入程序,而不是使用StringBuilder创建自己的缓冲
  • 按整数序号引用结果集中的列。某些驱动程序在解析列名时速度可能较慢

  • 分析通常是唯一确定事情进展缓慢的方法。然而,在这个例子中,我建议两件事是低挂果实:

  • 直接写入缓冲写入程序,而不是使用StringBuilder创建自己的缓冲
  • 按整数序号引用结果集中的列。某些驱动程序在解析列名时速度可能较慢

  • 直接写入
    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();
        }
    }