19

PageRequest で Spring Data を使用しており、非常に大きなデータセットにヒットしています。総ページ数を取得するために実行されるクエリを除いて、すべてのクエリが最適に実行されます。この機能を無効にする方法はありますか? それとも、独自の 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 を使用することであると考えています。これにより、開始行と返されるレコード数を設定できるようになります。次のページが利用可能かどうかだけが必要なので、追加のレコードを 1 つ取得するだけです。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 仕様を使用) でのカウント パフォーマンスの低下を回避できました。

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 はどちらも 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 に答える