6

Próbuję poprawić zapytanie n + 1 o projekcie, nad którym pracuję. Używam Hibernate z modelem pokazanym poniżej i chcę wyrazić zapytanie, aby odzyskać wszystkie pozycje związane z portfelem, w tym dwie ostatnie ceny dla każdej pozycji (cena na podaną datę i poprzednią cenę).Próbuję zoptymalizować zapytanie N + 1 w Hibernate

enter image description here

Przykład API:

List<Items> items = findItemsWithLatestTwoPrices(portfolio, latestPriceDate); 

Obecnie używam jedną kwerendę, aby wyodrębnić wszystkie elementy związane z portfela, a potem iteracyjne nad tymi pozycjami kwerendy dwie aktualne ceny na danej pozycji (więc n + 1).

Próbowałem wyrażając to w rodzimym języku SQL za pomocą podzapytania skorelowane, ale wydajność była straszna. To i fakt, że każdego dnia pojawiają się nowe ceny (a więc zapytanie staje się coraz wolniejsze) doprowadziło mnie do wniosku, że potrzebuję innego modelu, ale staram się wymyślić model, który jest rozsądnie skuteczny i stały w miarę upływu czasu. liczba wzrostów cen.

myślałam o różnych rozwiązań w tym reprezentujący ceny jak połączonych listach, lub za pomocą jakiegoś drzewa, ale uważam, że są lepsze alternatywy. Czy brakuje mi czegoś oczywistego? Czy ktoś pracujący nad podobnym problemem wymyślił dobre rozwiązanie?

I naprawdę nie obchodzi pogoda używam HQL lub natywnego SQL tak długo jak wydajność jest przyzwoity. Jestem również otwarty na zmiany w modelu.

Dzięki!

[Edytuj]

Ponieważ mam ponad dwa lata danych dotyczących cen, a tam może być 1000+ pr przedmiotów. portfolio, pobranie całego wykresu prawdopodobnie nie jest dobrym pomysłem. Potrzebuję także dostępu losowego według daty, więc przechowywanie dwóch cen jako pól na produkcie nie jest niestety opcją.

Odpowiedz

0

Nie jestem pewien, czy łapię wszystkie twoje wątpliwości, ale jak prawdopodobnie doszliście do wniosku, nie ma prostego rozwiązania w przypadku Hibernate. Sprowadzi się do twojego modelowania domeny. Myślę, że najlepiej jest oddzielić normalny przypadek i specjalny przypadek. Możesz modelować je w swojej normalnej domenie lub użyć specjalnych reprezentacji w specjalnych przypadkach.

Za pobranie n ostatnich nagród próbowano ustawić rozmiar wsadu na relacji? Wykonaj relację uporządkowaną (ostatnią na górze), a następnie ustaw rozmiar wsadu na wartość podobną do 10. To spowoduje, że zapytanie Hibernate dla 10 i 10 wierszy oraz z indeksami na kluczu obcym i kolumnie zamówienia powinno działać w większości przypadków przypadki.

Wydaje mi się również, że można zachować dodatkowe relacje, a także cały zestaw. Nie bój się jawnie modelować ważnych relacji, takich jak "ceny z ostatnich miesięcy", mimo że byłoby to duplikowanie danych. W większości przypadków powinno być możliwe uniknięcie powielania w DB.

Aby uzyskać dostęp losowy w oparciu o daty, wydaje się, że najlepiej jest obsłużyć zapytanie niestandardowe zamiast dostępu przez model domeny, jeśli są zbyt wolne, należy rozważyć użycie buforowania drugiego poziomu, ale zgaduję, że wzór dostępu nie przyniesie z tego wiele korzyści.

0

Należy starać się odzyskać pozycje, a ceny w jednym zapytaniu. Jeśli to zrobisz, możesz powtórzyć swoje produkty i ich ceny bez konieczności wybierania dla każdego przedmiotu. Twój problem z n + 1 powinien zniknąć.

Na przykład, można użyć chętny pobierania ciągu zapytania lub definicji swojego stowarzyszenia.

Odnoszące się do zwiększenia wydajności troski obiektów cenowe. Być może możesz przechowywać ceny dwóch lajków w jednym lub dwóch dodatkowych polach swojej klasy przedmiotów. Wtedy możesz zawsze chętniej pobrać te dodatkowe pola i leniwy pobrać starsze ceny w swojej kolekcji, jeśli musisz.

+0

Cześć, dziękuję za odpowiedź. Mam pewne zastrzeżenia przeciwko pobieraniu całego wykresu. Ponieważ ceny są dostępne codziennie, a może być ich nawet 1000 i więcej, oznaczałoby to odzyskanie i utworzenie 73000 obiektów, jeśli masz dwa lata (jak mamy). Zmieniłem moje pytanie, aby dołączyć liczby. Jeśli chodzi o używanie pola dla dwóch cen, które jest pomocne tylko wtedy, gdy zawsze korzystasz z ceny dziennej, ale potrzebuję dostępu losowego według daty. – ebaxt

+0

Może najpierw załadujesz wszystkie elementy z portfolio, a następnie załadujesz wszystkie ceny z datą, której potrzebujesz (w niezależnym drugim zapytaniu). Następnie możesz dopasować przedmioty do cen w pamięci. Dzięki temu można uniknąć obciążenia n + 1. Poza tym nie widzę innej opcji z wyjątkiem szybkiego ładowania całego wykresu. – GeorgeG

0

Można wypróbować kilka opcji

  1. Ponieważ ceny są data oparty można spojrzeć na podział danych na db przez miesiąc. To znacznie pomoże w Twoich pytaniach, ponieważ liczba rekordów wyszukiwania cen znacznie by się zmniejszyła, zamiast patrzeć na całe 2 letnie ceny. Spróbuj po tym zapytaniu SQL. Również uruchom wyjaśnienie, aby upewnić się, że trafiłeś w odpowiednie indeksy itp.
  2. Czy brałeś pod uwagę caching (np. Memcache)? Możesz wstępnie wczytać ceny przedmiotów za bieżącą & poprzednią cenę do pamięci podręcznej. Następnie możesz pobrać portfel, pozycje & cache wyszukiwania dla cen, które powinny być dość szybkie.
0

Jeśli używasz Postgre lub Oracle, możesz łatwo użyć analytic/windowing function w tych cenach po dołączeniu do nich, pobierając pierwsze dwie wartości. Dopóki kolumna dla ORDER BY jest indeksowana, powinna dać wystarczająco dobrą wydajność.

P.S. Następnym razem, jeśli powiesz, że rozważasz użycie natywnego SQL - dodaj dostawcę/wersję DB.

Powiązane problemy