【发布时间】:2013-03-03 16:59:55
【问题描述】:
问题:如何一次处理(读入)1000 条记录的批次,并确保只有当前批次的 1000 条记录在内存中?假设我的主键名为“ID”,而我的表名为Customer。
背景:这不是用于用户分页,而是用于编译有关我的表格的统计信息。我的可用内存有限,因此我想一次读取 1000 条记录的记录。我只是在阅读记录,它们不会被修改。我读过StatelessSession 适合这种事情,我听说有人使用ScrollableResults。
我尝试过的内容: 目前我正在开发一个定制的解决方案,在该解决方案中我实现了 Iterable,并且基本上使用 setFirstResult 和 setMaxResults 进行了分页。这对我来说似乎很慢,但它允许我一次获得 1000 条记录。我想知道如何更有效地做到这一点,也许像ScrollableResults 这样的东西。我还不确定为什么我目前的方法这么慢;我按 ID 排序,但 ID 是主键,所以表应该已经被索引了。
如您所知,我一直在阅读有关如何执行此操作的零碎文章。如果有人可以为我提供一个完整的方法来做到这一点,将不胜感激。我知道你必须在ScrollableResults 上设置FORWARD_ONLY 并且调用evict(entity) 会占用一个实体的内存(除非你正在做二级缓存,我还不知道如何检查我是否是或不)。但是,我在 JavaDoc 中看不到任何方法可以一次读取 1000 条记录。我希望在可用内存不足和网络性能缓慢之间取得平衡,因此一次通过网络发送一条记录真的不是这里的选择。我尽可能使用 Criteria API。感谢您的详细回复。
【问题讨论】:
-
旁注,如果有人能指出 cmets 中“一次滚动浏览记录 X”的适当术语,将不胜感激。我认为它被称为批处理,但 Hibernate 文档仅在其批处理部分中提到更新和删除...
-
这是一种批处理/分页的形式,只是它可能不是一个很常见的请求。我需要这样做,最后只是获取内存中的所有 PK 并执行大量
where Id in (...)查询。 -
另外,仅仅因为您的表由 PK 索引并不一定意味着记录在内部由 PK 排序。该表可能使用可扩展散列索引。即使这听起来不太可能,B+-树似乎更常见。此外,查询可能会在某个时候使用与 PK 不同的索引进行过滤,这意味着之后仍需要对结果进行重新排序。 (例如,如果您选择日期范围内的记录,它们将从按日期排序的表中检索。) EXPLAIN 应该清除它。
-
@millimoose oracle 文档似乎另有说明(关于 PK 始终是索引)
-
我并不是说 PK 没有被索引。我是说它可能不是在执行查询时首先访问的索引。 (这将在应用排序之前确定元素的顺序。)