19

我们将 Spring Data 与 PageRequest 一起使用,并获得了大量数据。除了为获取总页数而执行的查询外,所有查询都以最佳方式执行。有没有办法禁用此功能,或者我们很可能必须实现自己的 Pageable?

http://static.springsource.org/spring-data/data-commons/docs/1.3.2.RELEASE/api/org/springframework/data/domain/PageRequest.html

http://static.springsource.org/spring-data/data-commons/docs/1.3.2.RELEASE/api/org/springframework/data/domain/Pageable.html

编辑: 经过进一步分析,我认为解决此问题的唯一方法是不使用 Spring Data 并使用 EntityManager,因为它允许设置起始行和返回的记录数。我们只需要下一页是否可用,因此我们只需检索一条额外的记录。我们还需要一个动态查询,这在 Spring Data 中似乎是不可能的。

编辑2:似乎我只是没有等待足够长的时间来获得一些回应。多谢你们!!!

4

3 回答 3

39

实现这一点的方法是简单地使用List作为返回值。例如,对于这样定义的存储库:

interface CustomerRepository extends Repository<Customer, Long> {

  List<Customer> findByLastname(String lastname, Pageable pageable);
}

查询执行引擎将应用提交的偏移量和页面大小,Pageable但不会触发额外的计数查询,因为我们不需要构造Page实例。这也记录在参考文档的相关部分中。

更新:如果您想要下一页/上一页Page但仍跳过计数查询,您可以将Slice其用作返回值。

于 2012-09-29T12:36:27.300 回答
2

我能够避免动态查询(使用 Spring Data Specifications)中的计数性能下降,并在几篇文章中指出了基本存储库解决方案。

public class ExtendedRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {

    private EntityManager entityManager;

    public ExtendedRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public List<T> find(Specification<T> specification, int offset, int limit, Sort sort) {
        TypedQuery<T> query = getQuery(specification, sort);
        query.setFirstResult(offset);
        query.setMaxResults(limit);
        return query.getResultList();
    }

}

使用这种方法从 6M 记录数据集中检索 20 个记录切片的查询需要几毫秒。在 SQL 中运行相同的过滤查询。

使用类似的实现Slice<T> find(Specification<T> specification, Pageable pageable)需要 10 多秒。

类似的实现返回Page<T> find(Specification<T> specification, Pageable pageable)大约需要 15 秒。

于 2021-01-07T17:27:44.980 回答
1

我最近有这样的要求,最新的spring-boot-starter-data-jpa库提供了开箱即用的解决方案。没有count特征分页可以使用org.springframework.data.domain.Slice界面来实现。

摘自博客

根据您在应用程序中使用的数据库,它可能会随着项目数量的增加而变得昂贵。为了避免这种代价高昂的计数查询,您应该改为返回一个 Slice。与 Page 不同,Slice 只知道下一个 slice 是否可用。此信息足以遍历更大的结果集。Slice 和 Page 都是 Spring Data JPA 的一部分,其中 Page 只是 Slice 的一个子接口,带有几个附加方法。如果您不需要项目和页面的总数,则应该使用 Slice。

@Repository
public interface UserRepository extends CrudRepository<Employee, String> {

    Slice<Employee> getByEmployeeId(String employeeId, Pageable pageable);

}

使用 Slice#hasNext 浏览更大结果集的示例代码片段。在 hasNext 方法返回 false 之前,请求的查询条件可能存在数据。

        int page = 0;
        int limit = 25;
        boolean hasNext;
        do {
            PageRequest pageRequest = PageRequest.of(page, limit );
            Slice<Employee> employeeSlice = employeeRepository.getByEmployeeId(sourceId, pageRequest);
            ++page;
            hasNext = employeeSlice .hasNext();
        } while (hasNext);

于 2020-03-25T14:07:50.633 回答