提高此方案性能的方法

时间:2014-09-25 11:09:42

标签: java performance for-loop map

我的地图中填充了大量数据(大约300,000条记录)

并按以下方式迭代,

    for (Map.Entry<String, List<ClassOBj>> entry : testMap
                    .entrySet()) {
 // send email with map keys as email'id
 // email content is populated from the list
// Perform a sql update to the column with the dyanamic value generated here with the email'id
                                  }

如上所述,我担心在for循环内执行上述操作会导致性能问题。

更新

情景是。我正在迭代一个包含大量数据的地图,

在迭代它时,我得到用户ID,我必须计算用户ID。例如,考虑userid+some constants,这应该在数据库表中更新。

也应该添加到电子邮件内容以及我的地图中的列表值

所以我认为批量更新是不可能的,我的理解是否正确?

我应该遵循这种方法吗?或者选择任何其他想法

6 个答案:

答案 0 :(得分:2)

而不是在每个循环中更新数据库。尝试在完成循环后更新数据库。

优化大型数据库更新的方法有很多种。 最好的一个是

  • 将修改后的值插入临时表
  • 从临时表
  • 更新原始表

还使用基于线程的排队机制发送电子邮件

答案 1 :(得分:2)

由于两个原因,for循环需要时间 1)个人电子邮件通过减少运输连接来改善它 2)个人提交改进

所以理想的是处理两者,我建议你做1000批次,然后玩数字

示例

int BATCH_SIZE = 1000
conn = DriverManager.getConnection("username","password");
conn.setAutoCommit(false);
Statement stmt = conn.createStatement(
        ResultSet.TYPE_SCROLL_INSENSITIVE,
        ResultSet.CONCUR_UPDATABLE);
int count = 0;

Map<String, String> emails_map = new HashMap(BATCH_SIZE)<String, String>;
for (Map.Entry<String, List<ClassOBj>> entry : testMap
        .entrySet()) {
    String email = get_useremail();
    String const_val = do_magic(); // this is how you are computing some constant
    String body = construct_body();

    count++;
    String SQL = "YOUR UPDATE STATEMENT";
    stmt.executeUpdate(SQL);  
    emails_map.put(email, body); // can create 
    if (count % BATCH_SIZE == 0) {
        //commits all transcations
        conn.commit();
        //bulk send emails sending 
        //http://stackoverflow.com/questions/13287515/how-to-send-bulk-mails-using-javax-mail-api-efficiently-can-we-use-reuse-auth

        bulk_emails_send(emails_map)
    }

}


public void bulk_emails_send(Map<String, String> emails_map) {
    // Get the default Session object through your setting
    Session session = Session.getDefaultInstance(properties);
    Transport t = session.getTransport();
    t.connect();
    try {
        for (String email_id in emails_map) {
            Message m = new MimeMessage(session);
            //add to, from , subject, body
            m.saveChanges();
            t.sendMessage(m, m.getAllRecipients());
        }
    } finally {
        t.close();
    }
}

答案 2 :(得分:1)

我的建议是你可以使用Stored procedure。或者使用可以使用批量更新代替此。

有关sql batch update的更多信息。

答案 3 :(得分:1)

您应该使用jdbc批量更新功能。

在迭代地图时,您可以将批处理添加到预准备语句中。当您添加(比方说)2000条记录时,您调用stmt.batchUpdate(),它将以快速方式更新2000条不同的记录。

您可以在此处看到一些示例:

http://www.mkyong.com/jdbc/jdbc-preparedstatement-example-batch-update/

第二件事 - 如果可以的话,在每个batchUpdate之后进行事务提交。对于数据库配置,300k记录的事务可能很多。将此更新拆分为多个事务将具有更好的性能 - 但前提是您不能在所有记录上进行事务处理。

答案 4 :(得分:1)

我会做这样的事情。准备操作数据。

我想您正在更新一个应该具有唯一ID的用户表。

Map<String, String> emailIds = new HashMap<String, String>();
Map<String, String> emails = new HashMap<String, String>();
for (Map.Entry<String, List<ClassOBj>> entry : testMap.entrySet()) {
 -- DONOT DO THIS// send email with map keys as email'id
 -- DONOT DO THIS// email content is populated from the list
 -- DONOT DO THIS// Perform a sql update to the column with the dyanamic value generated here with the email'id
emails.put(emailId, content);
emailIds.put(id, emailId);

}

bulkEmailSend(emails);
bulkEmailUpdate(emailIds);

bulkEmailSendbulkEmailUpdate是应该编写以进行适当调用的方法。

因此,使用批量电子邮件发送和批量emailId更新方法将值更新回数据库。

答案 5 :(得分:1)

我将尝试总结上面提到的所有优点。

您的选择是,

  1. 尽可能使用多线程,但请记住,多线程会带来额外内存的成本(堆叠和应用程序将会关闭)。
  2. 另一个不错的选择是使用批量更新,但批量更新会带来数据库端锁定时间更长的成本。所以明智地使用它,因为线程将等待一个线程完成更新,因为更新将采用独占锁定,即不可能共享。

  3. 尝试与异步作业一起进行线程处理(特别是对于邮件) 尝试使用不同的服务器/进程进行邮件处理并异步向邮件服务器发送邮件请求,这非常快,因为您的邮件生成任务由其他进程处理(在实际邮件交换中可以接受一些延迟,因此允许您的慢速邮件服务器但应用程序服务器不是。)

  4. 如果可能的话,在DB服务器上的存储过程中移动完整的Db更新逻辑,这将节省您的大量时间 (经验法则:总是让A处理设计/优化A的任务,即数据库设计用于比pgming语言更快的数据库操作。)

  5. 无法根据您的需要给出答案,但我希望这有助于改善它:)