性能问题-用java在unix box中编写巨大的csv文件时花费太多时间,请与MYSQL DB交互以对每条记录进行交叉检查
我的Java应用程序读取了大约6-7MB的巨大csv文件大小,有50k到60k条记录,中间连接到mysql数据库,对每条记录进行交叉检查,只需选择查询并执行一些操作,将所有记录写入tmp csv文件。但这里的问题是,这个过程大约需要6-7个小时来编写tmp文件 示例代码-性能问题-用java在unix box中编写巨大的csv文件时花费太多时间,请与MYSQL DB交互以对每条记录进行交叉检查,java,mysql,performance,unix,jdbc,Java,Mysql,Performance,Unix,Jdbc,我的Java应用程序读取了大约6-7MB的巨大csv文件大小,有50k到60k条记录,中间连接到mysql数据库,对每条记录进行交叉检查,只需选择查询并执行一些操作,将所有记录写入tmp csv文件。但这里的问题是,这个过程大约需要6-7个小时来编写tmp文件 示例代码- public static void updateTransactionCsvFiles(String inputFilePath , String existingFileName,File outputFolder,Fil
public static void updateTransactionCsvFiles(String inputFilePath , String existingFileName,File outputFolder,File archiveFolder,String tpName) throws IOException {
File inputFile = new File(inputFilePath);
Charset charset = Charset.forName("UTF-8");
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), charset));
CSVReader reader = new CSVReader(in, '|','"');
List<String[]> csvBody = reader.readAll();
File newFile = new File("tmp.csv");
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(newFile), charset),32768);
CSVWriter writer = new CSVWriter(bw, '|',CSVWriter.NO_QUOTE_CHARACTER);
Connection connection = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver"); // JDBC Type4
connection = DriverManager.getConnection("jdbc:mysql://"+dbhostname+"/db",dbusername,dbpassword);
}catch(Exception e){
e.printStackTrace();
}
for(int row=0 ; row < csvBody.listSize; row++){
String eachRecord[]= csvBody.get(row);
String array[]= csvBody.get(row);
array = Arrays.copyOf(array, array.length + 1); //create new array from old array and allocate three more element
array[array.length - 1] = "brandName";
csvBody.remove(row);
csvBody.add(row, array);
String customerId = eachRecord[3];
List tpList = new ArrayList();
tpList.add("100");
StringBuilder builder = new StringBuilder();
for( int i = 0 ; i < tpList.size(); i++ ) {
builder.append("?,");
}
String query = "select customer_id from customer where client_id IN " +
"("
+ builder.deleteCharAt( builder.length() -1 ).toString() + ")"+" and customer_id = ? ";
PreparedStatement pstmt =connection.prepareStatement(query);
pstmt.setObject(index,customerId);
rs = pstmt.executeQuery();
String pid ="";
while(rs.next()){
pid=rs.getInt(3);
}
csvBody.get(row)[4] = pid;
pstmt =con.prepareStatement(""SELECT status, senttime, process_id FROM feed WHERE customer_id = ? and sent_time =(select MAX(senttime) FROM feeds WHERE customer_id = ? ) "");
pstmt.setObject(1,customerId);
pstmt.setObject(2,customerId);
rs = pstmt.executeQuery();
while(rs.next()){
feedstatus = rs.getString(1);
senttime = rs.getTimestamp(2);
processid =rs.getInt(3);
}
csvBody.get(row)[6] = feedstatus;
rs.close();
pstmt.close();
}
writer.writeAll(csvBody); // write all records in to the file.
writer.flush();
writer.close();
csvBody.clear();
csvBody = null;
reader.close();
}
我建议进行以下更改: 不需要一次读取文件的所有行并进行处理。相反,您可以逐行读取它,执行查询并将其写入文件。这正是BufferedReader应该使用的方式。 您正在使用csvBody.removeow;和csvBody.addrow,数组;这不是一个好的做法。我们不应该修改正在迭代的集合。 您不需要为每次迭代创建新的PreparedStatement对象。您可以在for循环之外声明它,并通过设置参数在每次迭代中执行它。 csvBody.clear;不需要,因为我们不会阅读所有的行。 如果还没有索引,您可能需要在client_id列上添加索引。 下面是一个如何逐行读取巨大csv文件的示例:
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), charset));
CSVReader reader = new CSVReader(in, '|','"');
String [] nextLine;
while ((nextLine = reader.readNext()) != null) {
//Process line
}
我注意到,当这个代码部署在QA环境中时,这个过程需要15-20分钟才能完成。但是,虽然在生产环境中部署相同的代码,但相同的过程需要6-7个小时,因为prod拥有大量的客户数据:使用2-3个select查询执行某些验证时,DBmysql交互时的最大时间消耗似乎是最大的;在prod env上花费了太多的时间。我是否应该使用hibernate而不是jdbc来缓存这些多查询select语句的输出,这样它就不会每次都命中数据库来获取结果?还是应该使用可调用stmt的存储过程?请建议是否需要实施任何其他解决方案以减少处理时间。或者我是否需要进行查询优化?如果需要,则如何进行我已从for循环中取出所有PreparedStatement查询,并在循环之前初始化所有PreparedStatement,但没有看到任何性能改进:您需要添加逐行处理文件的循环,而不是将所有内容都读入列表。这应该会显著提高性能。我也尝试过逐行循环处理文件,但现在性能降低了,甚至时间增加了都没有改善:应用程序与prod数据库交互时,似乎消耗了最长的时间,因为它有大量数据。您正在查询客户端id,该表在该列上有索引吗?如果没有,您可以尝试添加一个吗?