sql >> データベース >  >> RDS >> PostgreSQL

ヒントHINT_PASS_DISTINCT_THROUGHは、PageRequestに対してページごとに返されるエンティティの量を構成されたページサイズ(PostgreSQL)未満に減らします。

    実験している問題は、HINT_PASS_DISTINCT_THROUGHの使用方法に関係しています。 ヒント。

    このヒントを使用すると、DISTINCTがHibernateであることを示すことができます。 SELECTではキーワードを使用しないでください データベースに対して発行されたステートメント。

    この事実を利用して、DISTINCTに含まれていないフィールドでクエリを並べ替えることができます。 列リスト。

    しかし、それはこのヒントの使用方法ではありません。

    このヒントは、DISTINCTを適用するかどうかに違いがないことが確実な場合にのみ使用する必要があります。 SQLのキーワードSELECT SELECTであるため、ステートメント ステートメントはすでにすべての個別の値をフェッチしますそれ自体 。アイデアは、不要なDISTINCTの使用を回避してクエリのパフォーマンスを向上させることです。 ステートメント。

    これは通常、query.distinctを使用したときに発生することです。 条件クエリのメソッドであり、join fetchingしている 子供の関係。 このすばらしい記事 @VladMihalceaのは、ヒントがどのように機能するかを詳細に説明しています。

    一方、ページングを使用すると、OFFSETが設定されます。 およびLIMIT -または基盤となるデータベースに応じて同様のもの-SQLSELECT データベースに対して発行されたステートメント。クエリの結果の最大数に制限されます。

    前述のように、HINT_PASS_DISTINCT_THROUGHを使用する場合 ヒント、SELECT ステートメントにはDISTINCTは含まれません キーワードと、あなたの結合のために、それはあなたの主要な実体の重複した記録を与える可能性があります。 query.distinctを使用しているため、このレコードは重複を区別するためにHibernateによって処理されます。 、そして実際には必要に応じて重複を削除します。これが、Pageableで要求されたよりも少ないレコードを取得する理由だと思います 。

    DISTINCTのように、ヒントを削除した場合 キーワードは、データベースに送信されるSQLステートメントで渡されます。メインエンティティの情報のみをプロジェクトする限り、LIMITで示されるすべてのレコードをフェッチします。 これが、常に要求された数のレコードを提供する理由です。

    fetch joinを試すことができます 子エンティティ(joinだけでなく) 彼らと)。これにより、DISTINCTの列で並べ替える必要のあるフィールドを使用できないという問題が解消されます。 キーワードに加えて、今では合法的にヒントを適用できるようになります。

    ただし、そうすると別の問題が発生します。結合フェッチとページ付けを使用してメインエンティティとそのコレクションを返す場合、Hibernateはデータベースレベルでページ付けを適用しなくなります。OFFSETは含まれません。 またはLIMIT SQLステートメントのキーワード。結果をメモリにページ付けしようとします。これは有名なHibernateHHH000104です 警告:

    HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
    

    @VladMihalceaは、これ の最後の部分で詳細に説明しています。 記事。

    彼はまた、あなたの問題に対する1つの可能な解決策、ウィンドウ関数を提案しました。

    ユースケースでは、Specificationを使用する代わりに s、アイデアはあなたがあなた自身のDAOを実装するということです。このDAOは、EntityManagerにアクセスする必要があるだけです。 、@PersistenceContextを挿入できるため、それほど大きな問題ではありません。 :

    @PersistenceContext
    protected EntityManager em;
    

    このEntityManagerを入手したら 、提供されたPageableに基づいて、ネイティブクエリを作成し、ウィンドウ関数を使用してビルドできます。 情報、データベースに対して発行される正しいSQLステートメント。これにより、並べ替えに使用するフィールドや必要なものについて、より多くの自由が得られます。

    最後に引用した記事が示すように、ウィンドウ関数はすべての市長データベースでサポートされている機能です。

    PostgreSQLの場合、公式ドキュメント<で簡単に見つけることができます。 / a> 。

    最後に、@ nickshoeによって実際に提案され、記事 彼は、並べ替えとページングのプロセスを2つのフェーズで実行することです。最初のフェーズでは、子エンティティを参照し、ページングと並べ替えを適用するクエリを作成する必要があります。このクエリを使用すると、プロセスの第2フェーズで、メインエンティティ自体を取得するために使用されるメインエンティティのIDを特定できます。

    前述のカスタムDAOを利用して、このプロセスを実行できます。



    1. OracleのNULLIF()関数

    2. ForInRangeと値のキーを使用してテーブルに挿入します

    3. MySQLトリガーの使用

    4. Oracleでトリガーを使用してテーブルへの変更をログに記録する