【问题标题】:Java , add half a million objects to ArrayList from sql QueryJava,从 sql Query 向 ArrayList 添加半百万个对象
【发布时间】:2018-01-10 13:52:07
【问题描述】:

我有一个包含 50 万条记录的结果集的查询,每条记录我都在创建一个对象并尝试将其添加到 ArrayList 中。

如何优化此操作以避免出现堆空间不足错误时的内存问题。

这是一段代码:

while (rs.next()) {
            lista.add(sd.loadSabanaDatos_ResumenLlamadaIntervalo(rs));
}  


    public SabanaDatos loadSabanaDatos_ResumenLlamadaIntervalo(ResultSet rs)
    {
    SabanaDatos sabanaDatos = new SabanaDatos();
    try {

        sabanaDatos.setId(rs.getInt("id"));
        sabanaDatos.setHora(rs.getString("hora"));
        sabanaDatos.setDuracion(rs.getInt("duracion"));     
        sabanaDatos.setNavegautenticado(rs.getInt("navegautenticado"));
        sabanaDatos.setIndicadorasesor(rs.getInt("indicadorasesor"));
        sabanaDatos.setLlamadaexitosa(rs.getInt("llamadaexitosa"));
        sabanaDatos.setLlamadanoexitosa(rs.getInt("llamadanoexitosa"));
        sabanaDatos.setTipocliente(rs.getString("tipocliente"));

    } catch (SQLException e) {
        logger.info("dip.sabana.SabanaDatos SQLException : "+ e);
        e.printStackTrace();
    }

    return sabanaDatos;
}

注意:使用list的原因是这是一个critic系统,我只能每2小时打一个电话给bd。我无权在短时间内对 bd 进行更多调用,但我需要每 10 分钟显示一次数据。示例:第一次查询10行,我在sql查询后每分钟显示1行。

我无权创建本地数据库、写入文件或其他...只是访问内存。

【问题讨论】:

  • 为了更好的内存管理使用 LinkedList
  • 为什么需要列表?之后你用它做什么?尝试直接在结果集迭代中做进一步处理。
  • 您没有向我们展示足够多的代码,我们无法优化任何东西。为什么你需要(或认为你需要)ArrayList 中的所有这些对象,同时?将这么多对象添加到 ArrayList 几乎肯定会破坏使用数据库的目的。
  • 如果问题是你只能每两个小时查询一次数据库,但想随时查询,解决方案可能是在本地制作自己的数据库并镜像真实的数据库
  • @Adelin 是的,这更有意义......如果大小是可预测的,可以预先指定容量......

标签: java performance arraylist


【解决方案1】:

首先 - 阅读 50 万个对象并不是一个好习惯

您可以考虑将要读取的记录数分解为小块

作为解决方案,您可以考虑以下选项

1 - 使用 CachedRowSetImpl - 它是相同的 resultSet ,保持 resultSet 打开是一种不好的做法(因为它是数据库连接属性)如果您使用 ArrayList - 那么您将再次执行操作并利用内存

有关 cachedRowSet 的更多信息,您可以转到

https://docs.oracle.com/javase/tutorial/jdbc/basics/cachedrowset.html

2 - 您可以考虑使用内存数据库,例如 HSQLDB 或 H2。它们非常轻量级和快速,提供了可以运行 SQL 查询的 JDBC 接口

对于 HSQLDB 实现,您可以检查

https://www.tutorialspoint.com/hsqldb/

【讨论】:

  • 谢谢,我认为 CachedRowSetImpl 可以作为一个选项,问题 CachedRowSetImpl 是否包含在 java 6 中?
  • 是的 - 你可以在这里找到它docs.oracle.com/javase/6/docs/api/javax/sql/rowset/…
  • 嗨@ivan,你试过了吗,有用吗..?如果它有效 - 性能如何......?
  • ,是的,我试过了。它的作品,但我做了一些改变更多的内存,在代码中使用列号循环。
【解决方案2】:

选项1:
如果您同时需要列表中的所有项目,则需要增加 JVM 的堆空间,例如在启动应用程序时添加参数 -Xmx2G (java -Xmx2G -jar yourApp.jar)。

选项2:
将sql拆分为多个调用

【讨论】:

  • 分割 sql 在这里没有帮助。他收到堆异常,因为他试图在列表中保存 半百万 个对象
  • 分割多个sql的想法是每次选择获得更少的结果,处理它们(例如保存在其他表中,与其他应用程序通信)并继续下一个选择。但也许在业务逻辑上是不可能的。
【解决方案3】:

将Strings 实习起来可能会有所帮助,两次出现的相同字符串只有一个对象。

public class StringCache {
    private Map<String, String> identityMap = new Map<>();

    public String cached(String s) {
         if (s == null) {
             return null;
         }
         String t = identityMap.get(s);
         if (t == null) {
             t = s;
             identityMap.put(t, t);
         }
         return t;
    }
}

StringCache horaMap = new StringCache();
StringCache tipoclienteMap = new StringCache();

    sabanaDatos.setHora(horaMap.cached(rs.getString("hora")));
    sabanaDatos.setTipocliente(tipoclienteMap .cached(rs.getString("tipocliente")));

增加内存已经说过了。

使用列号可以加快速度;如果需要,在循环之前从列名中获取一次 (rs.getMetaData())。

【讨论】:

  • 这样我不是将对象的数量增加到三 * n 行吗?
  • 取决于数据的重复性;做SELECT DISTINCT(hora) 或类似的计数。理想情况下是 100+n+10 个对象等。对于长(非重复文本),您可以考虑稍后查找,
【解决方案4】:

您的一些选择:

  1. 使用本地数据库,例如 SQLite。这是一个非常轻量级的数据库管理系统,易于安装 - 您不需要任何特殊权限即可 - 它的数据保存在您选择的目录中的单个文件中(例如保存 Java 应用程序的目录)并且可以用作大型 Java 数据结构(如 List)的替代方案。

  2. 如果您确实必须使用 ArrayList,请确保占用尽可能少的空间。请尝试以下操作:

    一个。如果您知道大致的行数,则使用适当的 initialCapacity 构造您的 ArrayList 以避免重新分配。估计您的数据库将增长到的最大行数,并在您的 initialCapacity 中再添加几百行以防万一。

    b.确保您的 SabanaDatos 对象尽可能小。例如,确保id 字段是int 而不是Integer。如果hora 字段只是一天中的某个时间,则它可以更有效地保存在short 中而不是字符串。对于其他领域也是如此,例如duracion - 如果它的范围允许,它甚至可以放入byte?如果您有多个标志/布尔字段,则可以将它们打包到单个 byteshort 作为位。如果你有很多重复的字符串字段,你可以按照 Joop 的建议实习。

    c。如果仍然出现内存不足错误,请使用 JVM 标志 -Xms-Xmx 增加堆空间。

【讨论】:

    猜你喜欢
    • 2016-06-28
    • 2022-08-19
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 2017-06-13
    相关资源
    最近更新 更多