sql >> Database teknologi >  >> RDS >> PostgreSQL

Tip HINT_PASS_DISTINCT_THROUGH reducerer mængden af ​​entiteter, der returneres pr. side for en PageRequest, ned til under den konfigurerede sidestørrelse (PostgreSQL)

Det problem, du eksperimenterer, har at gøre med den måde, du bruger HINT_PASS_DISTINCT_THROUGH på tip.

Dette tip giver dig mulighed for at angive Hibernate, at DISTINCT nøgleord bør ikke bruges i SELECT erklæring udstedt mod databasen.

Du udnytter dette faktum til at tillade, at dine forespørgsler sorteres efter et felt, der ikke er inkluderet i DISTINCT kolonneliste.

Men det er ikke sådan dette tip skal bruges.

Dette tip skal kun bruges, når du er sikker på, at der ikke vil være nogen forskel mellem at anvende eller ikke anvende en DISTINCT nøgleord til SQL SELECT sætning, fordi SELECT sætningen vil allerede hente alle de forskellige værdier i sig selv . Ideen er at forbedre ydelsen af ​​forespørgslen og undgå brugen af ​​en unødvendig DISTINCT erklæring.

Dette er normalt, hvad der vil ske, når du bruger query.distinct metode i dine kriterieforespørgsler, og du join fetching børneforhold. Denne fantastiske artikel af @VladMihalcea forklare, hvordan hintet fungerer i detaljer.

På den anden side, når du bruger personsøgning, vil den indstille OFFSET og LIMIT - eller noget lignende, afhængigt af den underliggende database - i SQL SELECT erklæring udstedt mod databasen, hvilket begrænser din forespørgsel til et maksimalt antal resultater.

Som nævnt, hvis du bruger HINT_PASS_DISTINCT_THROUGH tip, SELECT sætningen vil ikke indeholde DISTINCT søgeord, og på grund af dine joinforbindelser kan det potentielt give dublerede registreringer af din hovedentitet. Disse poster vil blive behandlet af Hibernate for at differentiere dubletter, fordi du bruger query.distinct , og det vil faktisk fjerne dubletter, hvis det er nødvendigt. Jeg tror, ​​at dette er grunden til, at du muligvis får færre poster end anmodet om i din Pageable .

Hvis du fjerner tippet, som DISTINCT nøgleordet sendes i SQL-sætningen, som sendes til databasen, så vidt du kun projekterer oplysninger om hovedenheden, vil det hente alle de poster, der er angivet med LIMIT og det er derfor, det altid vil give dig det ønskede antal poster.

Du kan prøve at fetch join dine underordnede enheder (i stedet for kun join med dem). Det vil eliminere problemet med ikke at kunne bruge det felt, du skal sortere efter i kolonnerne i DISTINCT søgeord, og derudover vil du være i stand til at anvende, nu lovligt, tippet.

Men hvis du gør det, vil det give dig et andet problem:Hvis du bruger join-hentning og paginering for at returnere hovedentiteterne og dets samlinger, vil Hibernate ikke længere anvende paginering på databaseniveau - det vil ikke inkludere OFFSET eller LIMIT nøgleord i SQL-sætningen, og den vil forsøge at paginere resultaterne i hukommelsen. Dette er den berømte Hibernate HHH000104 advarsel:

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

@VladMihalcea forklarer det meget detaljeret i den sidste del af dette artikel.

Han foreslog også en mulig løsning på dit problem, Window Functions .

I dit tilfælde, i stedet for at bruge Specification s, tanken er, at du implementerer din egen DAO. Denne DAO behøver kun at have adgang til EntityManager , hvilket ikke er meget, da du kan injicere din @PersistenceContext :

@PersistenceContext
protected EntityManager em;

Når du har denne EntityManager , kan du oprette indbyggede forespørgsler og bruge vinduesfunktioner til at opbygge, baseret på den medfølgende Pageable information, den rigtige SQL-sætning, der vil blive udstedt mod databasen. Dette vil give dig meget mere frihed med hensyn til, hvilke felter der bruges til sortering eller hvad du har brug for.

Som den sidst citerede artikel angiver, er vinduesfunktioner en funktion, der understøttes af alle borgmesterdatabaser.

I tilfælde af PostgreSQL kan du nemt støde på dem i den officielle dokumentation .

Til sidst en mulighed mere, faktisk foreslået af @nickshoe, og forklaret meget detaljeret i artikel han citerede, er at udføre sorterings- og personsøgningsprocessen i to faser:I den første fase skal du oprette en forespørgsel, der refererer til dine underordnede enheder, og hvor du vil anvende personsøgning og sortering. Denne forespørgsel vil give dig mulighed for at identificere id'erne for de vigtigste enheder, der vil blive brugt i anden fase af processen til at få selve hovedenhederne.

Du kan drage fordel af den førnævnte brugerdefinerede DAO til at udføre denne proces.



  1. Hvordan migrerer jeg MySQL-datamappe i docker-container?

  2. Rækker til kolonne i ORACLE

  3. INSERT med SELECT

  4. Tjek for overlappede datoer på en hvilken som helst række i en tabel Oracle SQL