2012-11-15 13 views
5

Mam zlecenia JPA w stosunku ManyToOne do Klienta. Jest dwukierunkowy, dzięki czemu Klient ma również zamówienia w polu OneToMany. Obie relacje używają pobierania EAGER (lub są w programie pobierania OpenJPA).zapobieganie wybiórcom N + 1 w JPA

Po wybraniu z zamówienia otrzymuję 1 opcję wyboru dla zamówień i N opcji dla pola Klient.orders. Ku mojemu zaskoczeniu ten problem występuje w OpenJPA, EclipseLink i Hibernate, nawet gdy używam JOIN FETCH (który działa w przypadku jednokierunkowym).

Czy istnieje dobry sposób rozwiązania tego problemu? Czy istnieją jakieś rozwiązania dotyczące rozwiązywania problemów z wyborem N + 1 w przypadku bardziej złożonych wykresów?

EDIT: Wyniki moich badań: - Na OpenJPA (którego używam) nie wiem rozwiązanie jeszcze - Na hibernacji @Fetch (FetchMode.SUBSELECT) rozwiązuje ten problem. Korzystanie z @BatchSize również pomaga, to wybiera określoną liczbę customer.orders pól w tym samym czasie. - Dla EclipseLink znalazłem podobną funkcję @BatchFetch (value = BatchFetchType.IN), ale nie pomaga w tym przypadku, przypuszczam, że nie może wydajnie obsłużyć tego w dwukierunkowej relacji.

+0

To jest trochę niewyraźne pytanie. Czy masz * jeden konkretny problem *, z którym chcesz pomóc, czy chcesz po prostu złożyć skargę na WZP? – millimoose

+0

Masz rację, byłem trochę sfrustrowany WZP, będę edytować moje pytanie, aby być bardziej na temat. –

+1

Czy naprawdę potrzebujesz pobierania EAGER na stronie Customer.orders? – Esteve

Odpowiedz

-1

W dowolnej strukturze ORM problem N + 1 jest powszechny. Nie możesz tego uniknąć. Ale, to jest więcej o tym, jakie podejście podejmiesz, aby rozwiązać problem. Możesz użyć asocjacji i leniwego obciążenia lub spodziewanej daty obciążenia na podstawie Twojej implementacji. Możesz także wykonać mapowanie bazy danych i pobrać wszystkie powiązane dane w jednym zapytaniu i możesz zmapować je do swojego Modelu. Ponieważ baza danych jest indeksowana, ta operacja może być szybsza niż pobieranie danych i mapowanie przy użyciu zapytań N + 1 (jeśli pozwala na to twoje opóźnienie sieci).

1

Spójrz na: What is SELECT N+1?, ponieważ jest tam wiele dobrych informacji.

Jeżeli Państwa wykorzystaniem Hibernate: Hibernate - Chapter 19: Improving Performance - Fetching Strategies

My own personal solution is to use native SQL and tmp ids table to dlatego, że ogólnie IMHO N + 1 Select Problem jest głównie problem z przetwarzaniem wsadowym. W przeciwnym razie leniwy ładunek (zazwyczaj roztwór N + 1) może być korzystny dla wydajności.

+1

Dziękuję, używanie natywnych zapytań mogłoby zdecydowanie pomóc. Ale wydaje się, że musisz napisać coś, co powinno być obowiązkiem ORM do wykonania. Może to doprowadzić do wielu prac ręcznych i koszmar utrzymania. –

+0

@SlowStrider Pomysł polega na tym, że nie powinieneś tego robić zbyt często. Nielegalne ładowanie N + 1 jest zazwyczaj właściwą metodą dla większości problemów. Poza tym, jeśli chodzi o efektywną i niezawodną optymalizację, okazuje się, że SQL (a nie JPA HQL) jest jedyną opcją ... więc nie rób tego, chyba że musisz. –

+0

Dla osób z niższych kręgów dobrze byłoby, gdybyś mógł mi powiedzieć dlaczego. Problem wyboru N + 1 nie może być magicznie naprawiony. Albo masz kartezjański produkt pól, albo leniwie ładujesz każdy obiekt. Nie jestem pewien, czego ludzie się spodziewają. Nie ma cholernej ORM, która mogłaby przewidzieć wydajność bazy danych i losowo zdecydować, kiedy zrobić chętny (produkt kartezjański), a nie leniwy (N + 1). Nie jestem pewien, czego ludzie się spodziewają. Przykro mi, ale nie mogłem po prostu podać fragmentu kodu, aby ten problem zniknął. –

0

Oto rozwiązanie:

  1. oddzielna warstwa podmiot od warstwy API i interakcji z instancje API wyłącznie w tobie aplikacji. Api w tym kontekście może być również określane jako DTO.

  2. Usuń relację całkowicie z Entity.

  3. Utwórz mechanizm wskazujący, że chcesz pobrać dzieci. Na przykład: propaguj fetchRequestList do warstwy, która odwzorowuje API na Entity (w ten sposób możesz pobierać warunkowo).

  4. Podczas wykonywania zapytania należy zebrać obiekty rodzica w normalny sposób.

  5. Pobranie całej kolekcji dzieci przy użyciu nazwanego sparametryzowanego zapytania z klauzulą ​​IN opartą na FK na nadrzędną PK.

  6. Prześledź wyniki i dopasuj je do rodziców.

Zmuszałoby to ORM do wykonywania zapytań n + 1, a nie n (n + 1) zapytań.Pamiętaj, że będziesz teraz musiał dodawać kaskadowe zapisywanie, usuwanie, aktualizowanie itp za pomocą niestandardowej logiki.

Powiązane problemy