PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Подсказка HINT_PASS_DISTINCT_THROUGH намалява количеството обекти, върнати на страница за PageRequest, до под конфигурирания размер на страницата (PostgreSQL)

Проблемът, който експериментирате, е свързан с начина, по който използвате HINT_PASS_DISTINCT_THROUGH намек.

Тази подсказка ви позволява да посочите на Hibernate, че DISTINCT ключова дума не трябва да се използва в SELECT извлечение, издадено срещу базата данни.

Вие се възползвате от този факт, за да позволите заявките ви да бъдат сортирани по поле, което не е включено в DISTINCT списък с колони.

Но този съвет не трябва да се използва така.

Тази подсказка трябва да се използва само когато сте сигурни, че няма да има разлика между прилагането или не на DISTINCT ключова дума към SQL SELECT израз, защото SELECT изразът вече ще извлече всички отделни стойности per se . Идеята е да се подобри производителността на заявката, като се избягва използването на ненужен DISTINCT изявление.

Това обикновено се случва, когато използвате query.distinct метод във вашите заявки за критерии и сте join fetching детски отношения. Тази страхотна статия на @VladMihalcea обяснете подробно как работи подсказката.

От друга страна, когато използвате страниране, той ще зададе OFFSET и LIMIT - или нещо подобно, в зависимост от основната база данни - в SQL SELECT изявление, издадено срещу базата данни, ограничаващо до максимален брой резултати на вашата заявка.

Както е посочено, ако използвате HINT_PASS_DISTINCT_THROUGH намек, SELECT изразът няма да съдържа DISTINCT ключова дума и, поради вашите съединявания, потенциално може да даде дублиращи се записи на основния ви обект. Тези записи ще бъдат обработени от Hibernate за разграничаване на дубликати, защото използвате query.distinct , и всъщност ще премахне дубликати, ако е необходимо. Мисля, че това е причината, поради която може да получите по-малко записи от изискваните във вашия Pageable .

Ако премахнете подсказката, като DISTINCT ключовата дума се предава в SQL израза, който се изпраща към базата данни, доколкото проектирате само информация за основния обект, тя ще извлече всички записи, посочени от LIMIT и ето защо винаги ще ви дава искания брой записи.

Можете да опитате да fetch join вашите дъщерни обекти (вместо само join с тях). Това ще елиминира проблема с невъзможността да използвате полето, по което трябва да сортирате в колоните на DISTINCT ключова дума и в допълнение ще можете да приложите, вече законно, подсказката.

Но ако го направите, ще имате друг проблем:ако използвате извличане на присъединяване и страниране, за да върнете основните обекти и колекциите им, Hibernate вече няма да прилага страниране на ниво база данни - няма да включва OFFSET или LIMIT ключови думи в SQL оператора и ще се опита да пагинира резултатите в паметта. Това е известният Hibernate HHH000104 предупреждение:

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

@VladMihalcea обяснява това много подробно в последната част на това статия.

Той също така предложи едно възможно решение на вашия проблем, Window Functions .

В случай на използване, вместо да използвате Specification s, идеята е да внедрите свой собствен DAO. Този DAO трябва да има достъп само до EntityManager , което не е много, тъй като можете да инжектирате своя @PersistenceContext :

@PersistenceContext
protected EntityManager em;

След като имате този EntityManager , можете да създавате собствени заявки и да използвате прозоречни функции за изграждане, въз основа на предоставения Pageable информация, правилният SQL оператор, който ще бъде издаден срещу базата данни. Това ще ви даде много повече свобода за това какви полета използват за сортиране или каквото и да е необходимо.

Както показва последната цитирана статия, Window Functions е функция, поддържана от всички кметски бази данни.

В случая с PostgreSQL можете лесно да ги намерите в официалната документация .

И накрая, още една опция, предложена всъщност от @nickshoe и обяснена много подробно в статия той цитира, е да извършите процеса на сортиране и страниране в две фази:в първата фаза трябва да създадете заявка, която ще препраща към вашите дъщерни обекти и в която ще приложите страниране и сортиране. Тази заявка ще ви позволи да идентифицирате идентификаторите на основните обекти, които ще бъдат използвани във втората фаза на процеса за получаване на самите основни обекти.

Можете да се възползвате от гореспоменатия персонализиран DAO, за да изпълните този процес.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PL/pgSQL изпълнение срещу изпълнение

  2. грешка при свързване с база данни, свързана с кодирането

  3. Как да премахнете няколко таблици в PostgreSQL с помощта на заместващ знак

  4. rake db:structure:dump се проваля под PostgreSQL / Rails 3.2

  5. PostgreSQL GIN индекс по-бавен от GIST за pg_trgm?