【问题标题】:Why is my JPA query getting slower on each loop iteration?为什么我的 JPA 查询在每次循环迭代时都会变慢?
【发布时间】:2015-05-18 10:00:31
【问题描述】:

我需要从 db 表中加载所有数据,然后将其放入索引中以进行搜索(具体为 elasticsearch)。 (在我的情况下,使用 ES 河流不是一种选择)

我的经历如下: 我有一个特定批次的查询(例如 5000 个条目)。我在循环中执行该查询以获取批次,每次迭代都会增加偏移量。第一次迭代大约需要 19 秒。第 4 次迭代已经是 50 秒了。

在我的情况下,该列有 700 万行,但生产数据至少会增加 3 倍,所以如果执行时间持续增长,我的方法将无济于事(已经有 700 万个条目)。 稍后我可以肯定地使用多个线程来选择数据,但首先我想保持每次选择的时间不变(如果可能的话)。

我想知道性能损失来自何处以及如何避免或至少将其最小化?

我从中选择的表只有一个 id (long) 和一个 document (clob) 列。

我正在使用包含 700 万行的 h2,也许这就是原因?我不熟悉 h2 在这种表大小上的性能。

我的第一个猜测是垃圾收集器,所以我用 VisualVM 看了看……不过看起来还不错。 已经尝试在每次迭代时清除会话工厂中的所有缓存,但行为没有改变,所以我想我在这里走错了路。

EntityManager em = persistenceUtils.openEm();
//        em.setProperty("javax.persistence.cache.storeMode",      CacheStoreMode.BYPASS);
//        em.setProperty("javax.persistence.cache.retrieveMode",      CacheRetrieveMode.BYPASS);
    Query selectAll = em.createQuery("Select d from Document d order by d.id");

    List<Document> documents = selectAll.setFirstResult(0).setMaxResults(BATCH_SIZE).getResultList();
    List<ListenableActionFuture<BulkResponse>> bulkResponses = Lists.newArrayList(addBulkIndexRequests(documents, client));
    int i = 1;
    while(documents != null && !documents.isEmpty()) {
        long batchStartTime = System.nanoTime();
        documents = selectAll.setFirstResult(i*BATCH_SIZE).setMaxResults(BATCH_SIZE).getResultList();
        long batchEndTime = System.nanoTime();
        System.out.println("+++ SELECTED BATCH " + i + "in" + (batchEndTime - batchStartTime) / 1000000000.0 +  "SECONDS +++");
        addBulkIndexRequests(documents, client);
        System.out.println("+++ ADDED BATCH " + i + " +++");
        i++;
    }
    persistenceUtils.closeEm(em);

【问题讨论】:

  • 在处理完每个页面后尝试EntityManager.clear(),否则每个数据都保留在持久化上下文中。也可能是H2的问题。
  • 调用EnttityManager.clear() 不会改变我看到的行为。我也试过SessionFactory.getChage().evictAll(),也没有运气。
  • 除了@AndreiI 的建议之外,您还可以尝试在查询中仅选择 id(因为 order by,这是此查询中的主要性能影响因素),并在循环中执行类似的操作List&lt;Document&gt; = em.createQuery("select d from Document d where d.id in :ids").setParameter(&lt;previously selected ids &gt;).getResultList()
  • @Predrag Marcic,这已经有点帮助了......能够以几乎恒定的时间处理 26 个批次。在第 27 批时,它突然跳到某个时间,就像时间的两倍。

标签: java jpa h2


【解决方案1】:

似乎 H2 是这里的问题。在本地安装了一个 oracle 11g 并针对它运行了选择查询。每批 1000 个条目的访问时间持续约为 0.44 秒。

但必须说,我还在针对 oracle DB 测试的解决方案中实施了 Predrag marcic 和 Andrei 的建议。

【讨论】:

    猜你喜欢
    • 2021-10-14
    • 2020-01-12
    • 2011-10-11
    • 1970-01-01
    • 2011-08-16
    • 2014-01-28
    • 2020-01-05
    • 1970-01-01
    • 2016-07-04
    相关资源
    最近更新 更多