为什么我的 JPA 查询在每次循环迭代时变慢?
Why is my JPA query getting slower on each loop iteration?
我需要从数据库 table 加载所有数据,然后将其放入索引中进行搜索(具体为 elasticsearch)。
(在我的情况下,使用 ES river 不是一个选项)
我的经历是这样的:
我有一个特定批次 sice 的查询(例如 5000 个条目)。我在循环中执行该查询以获取批次,每次迭代都会增加偏移量。第一次迭代大约需要 19 秒。第 4 次迭代已经大约 50 秒了。
在我的例子中,该列有 700 万行,但生产数据至少会增加 3 倍,因此如果执行时间持续增长,我的方法将无济于事(700 万行)条目已经)。
稍后我可以肯定地使用多个线程 selecting 数据,但首先我想保持每个 select 的时间不变(如果可能的话)。
我想知道性能损失从何而来以及如何避免或至少最小化它?
我 select 来自的 table 只有一个 id (long) 和一个文档 (clob) 列。
我正在使用其中包含 700 万行的 h2,也许这就是原因?我不熟悉 h2 在这种 table 大小上的性能。
我的第一个猜测是垃圾收集器,所以我用 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);
似乎 H2 是这里的问题。在本地安装了 oracle 11g,运行 select 对其进行了查询。每批 1000 个条目的访问时间始终约为 0.44 秒。
但不得不说,我在针对 oracle DB 测试的解决方案中也实施了 Predrag marcic 和 Andrei 的建议。
我需要从数据库 table 加载所有数据,然后将其放入索引中进行搜索(具体为 elasticsearch)。 (在我的情况下,使用 ES river 不是一个选项)
我的经历是这样的: 我有一个特定批次 sice 的查询(例如 5000 个条目)。我在循环中执行该查询以获取批次,每次迭代都会增加偏移量。第一次迭代大约需要 19 秒。第 4 次迭代已经大约 50 秒了。
在我的例子中,该列有 700 万行,但生产数据至少会增加 3 倍,因此如果执行时间持续增长,我的方法将无济于事(700 万行)条目已经)。 稍后我可以肯定地使用多个线程 selecting 数据,但首先我想保持每个 select 的时间不变(如果可能的话)。
我想知道性能损失从何而来以及如何避免或至少最小化它?
我 select 来自的 table 只有一个 id (long) 和一个文档 (clob) 列。
我正在使用其中包含 700 万行的 h2,也许这就是原因?我不熟悉 h2 在这种 table 大小上的性能。
我的第一个猜测是垃圾收集器,所以我用 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);
似乎 H2 是这里的问题。在本地安装了 oracle 11g,运行 select 对其进行了查询。每批 1000 个条目的访问时间始终约为 0.44 秒。
但不得不说,我在针对 oracle DB 测试的解决方案中也实施了 Predrag marcic 和 Andrei 的建议。