Select 使用 postgres 索引从偏移量到限制的所有记录

Select all records from offset to limit using a postgres index

我想从具有大约 40 列和 1.000.000 行的 table 中获取从偏移到限制的所有数据。我试图通过 postgres 索引 id 列并通过 java 和实体管理器获得我的 select 查询的结果。

我的查询需要大约 1 分钟才能得到结果,这有点太长了。我尝试使用不同的索引,并将我的查询限制为 100,但这次仍然需要。我该如何解决?我需要更好的索引还是我的代码有什么问题?

CriteriaQuery<T> q = entityManager.getCriteriaBuilder().createQuery(Entity.class);
TypedQuery<T> query = entityManager.createQuery(q);
List<T> entities = query.setFirstResult(offset).setMaxResults(limit).getResultList();

现在您可能根本没有使用索引。休眠 limit/offset 将如何转换为数据库操作存在一些歧义(参见 this comment in the case of postgres). It may imply overhead as described in detail in a reply to this post.

如果偏移量和限制与 id 列的值有直接关系,则可以在表单查询中使用它

SELECT e
FROM Entity
WHERE id >= offset and id < offset + limit

鉴于请求的记录数明显小于 table 中的记录总数,数据库将使用索引。

接下来是,40 列是相当多的。如果您实际上需要的要少得多,您可以定义一个仅包含所需属性的受限实体并查询该实体。这应该会减少一些开销。

如果您仍然不符合性能要求,您可以选择 jdbc connection/query 而不是使用休眠。

顺便说一句。您可以记录 jpa/hibernate 发出的实际 sql 并使用它从 postgress 获取 execution plan ,这将向您显示查询的实际情况以及是否使用索引.此外,您可以监控数据库的查询执行时间,以了解它消耗了哪些处理时间,哪些是由您的 java 客户端加上数据传输开销消耗的。

还有一种模仿offset+limit分页的技术,使用基于分页第一条记录的key的分页。

Map<Integer, String> mapPageTopRecNoToKey = new HashMap<>();

然后搜索记录 >= 页面的键并加载页面大小 + 1 条记录以找到下一页。

从第 1 页转到第 5 页需要更多的工作,但仍然很快。

这当然是一个糟糕的拼凑,但当时的技术确实是对某些数据库的速度提升。


在您的情况下,值得在 jpql 中指定所需的字段:select e.a, e.b 相当快。