sql >> Databáze >  >> RDS >> PostgreSQL

Tip HINT_PASS_DISTINCT_THROUGH snižuje množství entit vrácených na stránku pro PageRequest pod nakonfigurovanou velikost stránky (PostgreSQL)

Problém, který experimentujete, souvisí se způsobem, jakým používáte HINT_PASS_DISTINCT_THROUGH nápověda.

Tato nápověda vám umožňuje označit Hibernaci jako DISTINCT klíčové slovo by nemělo být použito v SELECT výpis vydaný proti databázi.

Využíváte této skutečnosti k tomu, abyste umožnili třídění vašich dotazů podle pole, které není zahrnuto v DISTINCT seznam sloupců.

Ale takhle by se tato nápověda neměla používat.

Tuto nápovědu je třeba použít pouze v případě, že jste si jisti, že nebude žádný rozdíl mezi použitím nebo nepoužitím DISTINCT klíčového slova do SQL SELECT příkaz, protože SELECT příkaz již načte všechny odlišné hodnoty per se . Cílem je zlepšit výkon dotazu a vyhnout se použití zbytečného DISTINCT prohlášení.

To se obvykle stane, když použijete query.distinct metoda ve vašich dotazech na kritéria a join fetching dětské vztahy. Tento skvělý článek @VladMihalcea podrobně vysvětlí, jak nápověda funguje.

Na druhou stranu, když používáte stránkování, nastaví OFFSET a LIMIT - nebo něco podobného, ​​v závislosti na podkladové databázi - v SQL SELECT prohlášení vydané proti databázi s omezením na maximální počet výsledků vašeho dotazu.

Jak je uvedeno, pokud použijete HINT_PASS_DISTINCT_THROUGH nápověda, SELECT příkaz nebude obsahovat DISTINCT klíčové slovo a kvůli vašim spojením může potenciálně poskytnout duplicitní záznamy vaší hlavní entity. Tyto záznamy budou zpracovány Hibernate za účelem rozlišení duplikátů, protože používáte query.distinct a v případě potřeby ve skutečnosti odstraní duplikáty. Myslím, že to je důvod, proč můžete získat méně záznamů, než je požadováno ve vaší Pageable .

Pokud nápovědu odstraníte, jako DISTINCT klíčové slovo je předáno v příkazu SQL, který je odeslán do databáze, pokud projektujete pouze informace o hlavní entitě, načte se všechny záznamy označené LIMIT a to je důvod, proč vám vždy poskytne požadovaný počet záznamů.

Můžete zkusit fetch join vaše podřízené entity (místo pouze join s nimi). Odstraní to problém s nemožností použít pole, podle kterého potřebujete seřadit ve sloupcích DISTINCT klíčové slovo a navíc budete moci použít, nyní legitimně, nápovědu.

Ale pokud tak učiníte, budete mít další problém:pokud použijete spojení načítání a stránkování k vrácení hlavních entit a jejich kolekcí, Hibernate již nebude používat stránkování na úrovni databáze – nebude zahrnovat OFFSET nebo LIMIT klíčová slova v příkazu SQL a pokusí se stránkovat výsledky v paměti. Toto je slavný Hibernate HHH000104 varování:

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

@VladMihalcea to velmi podrobně vysvětlil v poslední části toto článek.

Navrhl také jedno možné řešení vašeho problému, Funkce oken .

Ve vašem případě použití namísto použití Specification s, myšlenka je, že implementujete své vlastní DAO. Tento DAO potřebuje pouze přístup k EntityManager , což není moc, protože můžete vložit svůj @PersistenceContext :

@PersistenceContext
protected EntityManager em;

Jakmile budete mít tento EntityManager , můžete vytvářet nativní dotazy a používat funkce okna k sestavení na základě poskytnutého Pageable informace, správný SQL příkaz, který bude vydán vůči databázi. To vám dá mnohem větší svobodu ohledně toho, jaká pole se používají k třídění nebo co potřebujete.

Jak naznačuje poslední citovaný článek, funkce okna je funkce podporovaná všemi databázemi starostů.

V případě PostgreSQL na ně můžete snadno narazit v oficiální dokumentaci .

Nakonec ještě jedna možnost, kterou ve skutečnosti navrhl @nickshoe a velmi podrobně vysvětlenou v článek citoval, je provést proces řazení a stránkování ve dvou fázích:v první fázi musíte vytvořit dotaz, který bude odkazovat na vaše podřízené entity a ve kterém použijete stránkování a řazení. Tento dotaz vám umožní identifikovat ID hlavních entit, které budou použity ve druhé fázi procesu k získání samotných hlavních entit.

K provedení tohoto procesu můžete využít výše uvedené vlastní DAO.



  1. 5 způsobů, jak opravit chybu „Divide by zero“ v SQL Server (Msg 8134)

  2. Postup pro kontrolu neduplicitních řádků v tabulce před vložením (Oracle)

  3. Jak nainstalovat MySQL na Debian 8

  4. SQL dotaz pro výpočet zůstatku účtu