sql >> Database >  >> RDS >> PostgreSQL

Hint HINT_PASS_DISTINCT_THROUGH vermindert het aantal entiteiten dat per pagina wordt geretourneerd voor een PageRequest tot onder het geconfigureerde paginaformaat (PostgreSQL)

Het probleem dat u aan het experimenteren bent, heeft te maken met de manier waarop u de HINT_PASS_DISTINCT_THROUGH gebruikt hint.

Met deze hint kun je Hibernate aangeven dat de DISTINCT trefwoord mag niet worden gebruikt in de SELECT verklaring afgegeven tegen de database.

U maakt gebruik van dit feit om uw zoekopdrachten te laten sorteren op een veld dat niet is opgenomen in de DISTINCT kolomlijst.

Maar zo moet deze hint niet worden gebruikt.

Deze hint moet alleen worden gebruikt als u zeker weet dat er geen verschil zal zijn tussen het wel of niet toepassen van een DISTINCT sleutelwoord naar de SQL SELECT statement, omdat de SELECT statement haalt al de verschillende waarden per se . Het idee is om de prestaties van de zoekopdracht te verbeteren en het gebruik van een onnodige DISTINCT . te vermijden verklaring.

Dit is meestal wat er zal gebeuren als u de query.distinct . gebruikt methode in je criteriaquery's, en je bent join fetching kind relaties. Dit geweldige artikel van @VladMihalcea leggen in detail uit hoe de hint werkt.

Aan de andere kant, wanneer u paging gebruikt, wordt OFFSET . ingesteld en LIMIT - of iets dergelijks, afhankelijk van de onderliggende database - in de SQL SELECT verklaring afgegeven tegen de database, die uw zoekopdracht tot een maximum aantal resultaten beperkt.

Zoals vermeld, als u de HINT_PASS_DISTINCT_THROUGH hint, de SELECT statement bevat niet de DISTINCT trefwoord en, vanwege uw joins, kan het mogelijk dubbele records van uw hoofdentiteit opleveren. Deze records worden door Hibernate verwerkt om dubbele gegevens te onderscheiden, omdat u query.distinct gebruikt , en het zal in feite duplicaten verwijderen indien nodig. Ik denk dat dit de reden is waarom u mogelijk minder records krijgt dan gevraagd in uw Pageable .

Als u de hint verwijdert, zoals de DISTINCT sleutelwoord wordt doorgegeven in de SQL-instructie die naar de database wordt verzonden, voor zover u alleen informatie van de hoofdentiteit projecteert, zal het alle records ophalen die worden aangegeven door LIMIT en daarom krijgt u altijd het gevraagde aantal records.

Je kunt proberen en fetch join uw onderliggende entiteiten (in plaats van alleen join met hen). Het lost het probleem op dat u het veld waarop u moet sorteren niet kunt gebruiken in de kolommen van de DISTINCT zoekwoord en bovendien kunt u de hint nu legitiem toepassen.

Maar als u dit doet, krijgt u een ander probleem:als u samen ophaalt en paginering gebruikt om de belangrijkste entiteiten en de bijbehorende verzamelingen te retourneren, past Hibernate geen paginering meer toe op databaseniveau - het bevat geen OFFSET of LIMIT trefwoorden in de SQL-instructie, en het zal proberen de resultaten in het geheugen te pagineren. Dit is de beroemde Hibernate HHH000104 waarschuwing:

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

@VladMihalcea legt dat in detail uit in het laatste deel van dit artikel.

Hij stelde ook een mogelijke oplossing voor uw probleem voor, Window Functions .

In uw geval, in plaats van Specification . te gebruiken s, het idee is dat je je eigen DAO implementeert. Deze DAO hoeft alleen toegang te hebben tot de EntityManager , wat niet veel is, aangezien u uw @PersistenceContext . kunt injecteren :

@PersistenceContext
protected EntityManager em;

Zodra u deze EntityManager . heeft , kunt u native query's maken en vensterfuncties gebruiken om te bouwen, op basis van de meegeleverde Pageable informatie, de juiste SQL-instructie die tegen de database wordt uitgegeven. Dit geeft je veel meer vrijheid over welke velden worden gebruikt om te sorteren of wat je ook nodig hebt.

Zoals het laatst geciteerde artikel aangeeft, is Window Functions een functie die door alle grote databases wordt ondersteund.

In het geval van PostgreSQL kun je ze gemakkelijk tegenkomen in de officiële documentatie .

Eindelijk nog een optie, in feite voorgesteld door @nickshoe, en in detail uitgelegd in de artikel hij citeerde, is om het sorteer- en pagingproces in twee fasen uit te voeren:in de eerste fase moet je een query maken die verwijst naar je onderliggende entiteiten en waarin je paging en sortering toepast. Met deze zoekopdracht kunt u de ID's van de belangrijkste entiteiten identificeren die in de tweede fase van het proces worden gebruikt om de belangrijkste entiteiten zelf te verkrijgen.

U kunt profiteren van de eerder genoemde aangepaste DAO om dit proces te volbrengen.



  1. Hoe de gemiddelde verkoop per week te berekenen in MySQL

  2. Gebruik PARSENAME() om een ​​deel van een objectnaam terug te geven in SQL Server

  3. Totale rij toevoegen in MySQL

  4. Oracle sql-ontwikkelaarstool - gegevens niet beschikbaar na vastlegging