PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Hinweis HINT_PASS_DISTINCT_THROUGH reduziert die Anzahl der pro Seite zurückgegebenen Entitäten für einen PageRequest auf unter die konfigurierte Seitengröße (PostgreSQL)

Das Problem, mit dem Sie experimentieren, hat damit zu tun, wie Sie HINT_PASS_DISTINCT_THROUGH verwenden Hinweis.

Mit diesem Hinweis können Sie Hibernate angeben, dass der DISTINCT Schlüsselwort sollte nicht in SELECT verwendet werden Anweisung, die gegenüber der Datenbank ausgestellt wurde.

Sie nutzen diese Tatsache aus, damit Ihre Abfragen nach einem Feld sortiert werden können, das nicht im DISTINCT enthalten ist Spaltenliste.

Aber so sollte dieser Hinweis nicht verwendet werden.

Dieser Hinweis darf nur verwendet werden, wenn Sie sicher sind, dass es keinen Unterschied macht, ob Sie einen DISTINCT anwenden oder nicht Schlüsselwort zum SQL SELECT -Anweisung, weil die SELECT -Anweisung wird bereits alle eindeutigen Werte per se abrufen . Die Idee ist, die Leistung der Abfrage zu verbessern, indem die Verwendung eines unnötigen DISTINCT vermieden wird Aussage.

Dies geschieht normalerweise, wenn Sie query.distinct verwenden Methode in Ihren Kriterienabfragen, und Sie join fetching kindliche Beziehungen. Dieser großartige Artikel von @VladMihalcea erklären, wie der Hinweis im Detail funktioniert.

Wenn Sie dagegen Paging verwenden, wird OFFSET gesetzt und LIMIT - oder etwas ähnliches, abhängig von der zugrunde liegenden Datenbank - im SQL SELECT Anweisung, die gegenüber der Datenbank ausgegeben wird und Ihre Abfrage auf eine maximale Anzahl von Ergebnissen beschränkt.

Wie gesagt, wenn Sie den HINT_PASS_DISTINCT_THROUGH verwenden Hinweis, das SELECT -Anweisung enthält nicht den DISTINCT Stichwort und aufgrund Ihrer Verknüpfungen möglicherweise doppelte Datensätze Ihrer Hauptentität. Diese Datensätze werden von Hibernate verarbeitet, um Duplikate zu unterscheiden, da Sie query.distinct verwenden , und es werden bei Bedarf tatsächlich Duplikate entfernt. Ich denke, das ist der Grund, warum Sie möglicherweise weniger Datensätze erhalten, als in Ihrem Pageable angefordert werden .

Wenn Sie den Hinweis entfernen, als DISTINCT Schlüsselwort in der SQL-Anweisung übergeben wird, die an die Datenbank gesendet wird, sofern Sie nur Informationen der Hauptentität projizieren, werden alle Datensätze abgerufen, die durch LIMIT angegeben sind und deshalb erhalten Sie immer die angeforderte Anzahl von Datensätzen.

Sie können versuchen, fetch join Ihre untergeordneten Entitäten (anstatt nur join mit ihnen). Dadurch wird das Problem beseitigt, dass Sie das Feld, nach dem Sie sortieren müssen, in den Spalten des DISTINCT nicht verwenden können Schlüsselwort und außerdem können Sie jetzt berechtigterweise den Hinweis anwenden.

Aber wenn Sie dies tun, werden Sie ein weiteres Problem haben:Wenn Sie Join-Fetch und Paginierung verwenden, um die Hauptentitäten und ihre Sammlungen zurückzugeben, wird Hibernate keine Paginierung mehr auf Datenbankebene anwenden - es wird OFFSET nicht enthalten oder LIMIT Schlüsselwörter in der SQL-Anweisung, und es wird versucht, die Ergebnisse im Speicher zu paginieren. Dies ist das berühmte Hibernate HHH000104 Warnung:

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

@VladMihalcea erklärt das ausführlich im letzten Teil von diesem Artikel.

Er schlug auch eine mögliche Lösung für Ihr Problem vor, Window Functions .

Verwenden Sie in Ihrem Anwendungsfall anstelle von Specification s, die Idee ist, dass Sie Ihr eigenes DAO implementieren. Dieses DAO muss nur Zugriff auf den EntityManager haben , was nicht viel ist, da Sie Ihren @PersistenceContext einfügen können :

@PersistenceContext
protected EntityManager em;

Sobald Sie diesen EntityManager haben , können Sie native Abfragen erstellen und Fensterfunktionen zum Erstellen verwenden, basierend auf dem bereitgestellten Pageable Informationen, die richtige SQL-Anweisung, die für die Datenbank ausgegeben wird. Dies gibt Ihnen viel mehr Freiheit darüber, welche Felder zum Sortieren verwendet werden oder was auch immer Sie brauchen.

Wie der zuletzt zitierte Artikel zeigt, sind Fensterfunktionen eine Funktion, die von allen größeren Datenbanken unterstützt wird.

Im Fall von PostgreSQL finden Sie sie leicht in der offiziellen Dokumentation .

Zum Schluss noch eine Option, die tatsächlich von @nickshoe vorgeschlagen und ausführlich im Artikel Wie er zitierte, besteht darin, den Sortier- und Paging-Prozess in zwei Phasen durchzuführen:In der ersten Phase müssen Sie eine Abfrage erstellen, die auf Ihre untergeordneten Entitäten verweist und in der Sie Paging und Sortierung anwenden. Diese Abfrage ermöglicht es Ihnen, die IDs der Hauptentitäten zu identifizieren, die in der zweiten Phase des Prozesses verwendet werden, um die Hauptentitäten selbst zu erhalten.

Sie können das oben erwähnte benutzerdefinierte DAO nutzen, um diesen Prozess durchzuführen.