hibernate-fetchmode

FetchMode w Hibernate, czyli jak pobierać dane

Ten artykuł jest kontynuacją serii o Hibernate. W poprzedniej części pisałem o problem N + 1 zapytań. Teraz przyszedł czas na szczegółowe omówienie FetchMode.

W pierwszym artykule napisałem czym różni się FetchType od FetchMode. FetchMode jest parametrem, który określa, jak w relacji pobrać powiązane encje. Od tego, jak pobierzemy powiązane encje, zależy wydajność naszej aplikacji. Dlatego przy rozwiązywaniu problemów wydajnościowych w Hibernate, pierwszą rzeczą jaka może nam pomóc jest FetchMode.

 

FetchMode SELECT

Domyślnym trybem przy pobieraniu powiązanych encji jest FetchMode.SELECT. Każda powiązana encja (lub kolekcja encji) jest pobierania poprzez dodatkowe zapytanie SELECT. Ilość dodatkowych zapytań można sparametryzować poprzez adnotację @BatchSize, co opisałem bardzo szczegółowo w Hibernate i problem N + 1 zapytań.

 

FetchMode JOIN

Tryb join służy do zmiany domyślnego sposobu pobierania powiązanych encji w taki sposób, że generowane jest jedno zapytanie, które zawiera złączenie tabeli nadrzędnej i powiązanej.

Uwaga: jeśli pracujesz ze Spring Data, to @Fetch(FetchMode.JOIN) nie da żadnego efektu, gdy używasz metody findAll() z repozytorium JPA. Jest to spowodowane tym, że repozytoria Spring Data korzystają z criteria api, które generuje zapytania JPQL i FetchMode w tym przypadku jest ignorowany.
Podobnie jest z wszystkimi innymi metodami, które używają JPQL.

Jeśli użyjesz metody findById(id) zobaczysz, że zamiast dwóch zapytań select, zostało wykonane tylko jedno z left outer join.

hibernate-select-join

 

Jeśli chcesz uzyskać podobny efekt korzystając z metody findAll(), musisz niestety stworzyć odpowiednie zapytanie JPQL, np:

FetchMode SUBSELECT

Ostatnim trybem jest FetchMode.SUBSELECT. Tryb ten sprawia, że wykonają się dwa zapytania. Jedno do pobrania encji nadrzędnych, drugi do pobrania encji powiązanych. Jest to bardzo podobne ustawienie do FetchMode.SUBSELECT z ustawioną opcją @BatchSize, z tą różnicą, że FetchMode.SUBSELCET zawsze generuje jedno dodatkowe zapytanie, które pobiera wszystkie dodatkowe encje.

hibernate-subselect

 

Kiedy stosować odpowiedni FetchMode?

FetchMode SELECT

Domyślnego trybu można używać, kiedy pobieramy pojedyncze encje, wtedy pobieranie powiązań osobnymi zapytaniami nie jest problematyczne.

FetchMode SELECT z @BatchSize

Tego trybu możemy używać, kiedy przetwarzamy niewielkie ilości rekordów. Pamiętaj, że ta opcja jest zrealizowana poprzez słowo kluczowe IN (sql), które w większości baz danych może obsługiwać ograniczoną liczbę rekordów (zwykle jest to 1 tyś.).

FetchMode JOIN

Pozwala ograniczyć liczbę zapytań, ale jego konsekwencją może być większe obciążenie bazy danych bardziej skomplikowanymi zapytaniami.

FetchMode SUBSELECT

Możesz zastosować tę opcję, jeśli w powiązanej tabeli jest jakaś niewielka ilość rekordów i warto pobrać je wszystkie (w praktyce developerzy rzadko stosują tę opcję). Warto także dodać, że ta opcja działa tylko na kolekcjach.

 

Podsumowanie

Użycie odpowiedniego FetchMode może wydawać się wystarczające w wielu przypadkach, zwłaszcza tam, gdzie łączymy ze sobą nie więcej niż dwie tabele. Natomiast w bardziej skomplikowanych sytuacjach, często o wiele lepszym rozwiązaniem (moim zdaniem) jest skorzystanie z odpowiedniego zapytania JPQL. W każdym przypadku jednak, trzeba sprawdzić co działa lepiej, tak by osiągnąć jak najlepsze wyniki.

Zaktualizowałem też kod źródłowy testowej aplikacji na githubie: Hibernate Example.

 

Źródła:

https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#fetching-fetch-annotation

 

Zapisz się na Newsletter

Mateusz Dąbrowski

Cześć jestem Mateusz, zajmuję się programowaniem już ponad 12 lat i zachęcam Cię do lektury mojego bloga

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *