Czy należy zrezygnować z frameworku ORM, gdy trzeba zaimplementować operację zbiorczą?

15

Oto typowa sytuacja:

  • Musisz zaimplementować operację zbiorczą w aplikacji korzystającej ze struktury ORM.
  • Po pierwszym przejściu zauważyłeś znaczące problemy z wydajnością.

Oto moje pytanie:

  • Czy w tej sytuacji preferujesz rozwiązanie zawierające surowy SQL?
  • A może istnieją dobrze znane wzorce projektowe, które mogą pomóc w łagodzeniu problemów, które są zwykle związane z operacjami masowymi z platformami ORM?

EDYTOWAĆ:

  • Nie pytam, czy powinieneś usunąć framework ORM z całej aplikacji.
  • Pytam: czy należy zrezygnować z frameworku ORM dla tego niewielkiego wycinka aplikacji?
Jim G.
źródło
Nie wiem, czy powinieneś coś zrobić, ale czy próbowałeś grupować swoją masową operację?
ChrisAnnODell,

Odpowiedzi:

13

ORM nie mają na celu całkowitego przejęcia dostępu do bazy danych. Użyj ich do tego 80% kodu, który jest CRUD, co jest zbyt żmudne, by pisać samodzielnie. Używaj procedur przechowywanych, dynamicznego SQL lub cokolwiek chcesz dla pozostałych 20%, które należy dokładnie zoptymalizować.

Robert Harvey
źródło
4
Działałoby to, gdyby abstrakcja bazy danych nie była jednym z głównych powodów, dla których zdecydowano się na użycie ORM.
@ Pierre303, trudno mi zrozumieć twój komentarz. Co masz na myśli?
Mark Canlas
@MarkCanlas: Myślę, że ma na myśli „wyodrębnianie bazy danych” w tym sensie, że możesz zmienić bazę danych (np. Przejść z SQL Server do MySQL), jeśli chcesz to zrobić. W praktyce ten przypadek użycia rzadko występuje.
Robert Harvey
1
Nadal możesz tworzyć abstrakcje. Większość ORM, które faktycznie obsługują wielu dostawców / dialektów, obsługuje kod specyficzny dla dostawcy / dialektu. Możesz zaimplementować operacje jako wstawianie zbiorcze / wiązanie tablic / TVP / cokolwiek dla określonych baz danych i pozwolić, aby powracał do stanu powoli po zwolnieniu dla nieobsługiwanych dostawców, takich jak SQLite. W najgorszym przypadku możesz podzielić funkcjonalność, która może być masowa, na osobny interfejs / klasę i podrzędną w innej implementacji opartej na parametrach kompilacji lub konfiguracji.
Aaronaught
Tak, mogą pomóc niestandardowe dialekty, a także określony kod dla określonych problemów. Jednak, aby było to wykonalne z finansowego punktu widzenia, musi to być ograniczone do ścisłego minimum. Nasze niestandardowe funkcje niestandardowe (dialekty) stanowią mniej niż 0,1% całkowitej bazy kodów dostępu do danych. Byłbym naprawdę zaniepokojony, gdyby to było coś więcej.
7

Używam ORM (nHibernate) w aplikacji, która wymaga wysokiej wydajności i obsługuje miliardy rekordów. Z czasem zauważyliśmy, że najbardziej znaczące problemy z wydajnością były związane z naszym sposobem korzystania z ORM, a nie tylko z samego ORM.

ORM nie powinien zastępować obowiązkowej wiedzy o bazie danych. Jest to narzędzie, którego używasz, aby uzyskać większą produktywność i elastyczność w kodzie, ale musisz znać podstawowe procesy, aby zoptymalizować wydajność.

Nie określiłeś konkretnej ORM, więc oto, co zrobiliśmy, aby poprawić wydajność:

  • Użyliśmy profilera ORM. (użyliśmy nhprof)
  • Użyliśmy profilera bazy danych. (użyliśmy SQL Server Profiler)
  • Czytamy jak najwięcej artykułów na ten temat. (Wiele było dostępnych dla nHibernate oprócz całego rozdziału na ten temat w dokumentacji)
  • Kupiliśmy określone książki dotyczące wydajności i skalowalności.
  • Stworzyliśmy system testów porównawczych, aby przetestować własne optymalizacje.
  • a co ważniejsze, byliśmy w stanie przetestować nasz kod u prawdziwych klientów z ogromnymi danymi. Ta ostatnia rzecz pomogła nam dostrzec większość problemów w naszej aplikacji.
Dan McGrath
źródło
1

Udało nam się to zrobić za pomocą Entity Framework, ale nasza aplikacja wykonała wiele operacji w stylu wsadowym (zapisywaliśmy dużą liczbę rekordów do poszczególnych tabel), więc było dobrze. Zdecydowanie sprawdziłbym, czy byłoby możliwe zachowanie frameworku ORM, jeśli to możliwe, tylko po to, aby zmniejszyć ilość kodu specjalnego przeznaczenia w Twojej aplikacji. Czy można buforować zapisy, a następnie wykonać je jako grupę? Tracisz semantykę transakcji, ale jeśli wybierasz się do operacji masowych, zakładam, że już się z tym pogodziłeś.

TMN
źródło
1

ORM nie robią nic magicznego. Tłumaczą metody dostępu do obiektów na SQL. Wykonywane przez nich instrukcje SQL niekoniecznie są wolniejsze niż instrukcje SQL, które zapisuje się ręcznie. To powiedziawszy, jest kilka kwestii, na które możesz natknąć się:

  1. Transakcje: Jedna duża operacja masowa jest prawie zawsze szybsza niż wiele małych transakcji, które razem osiągają to samo. W związku z tym, jeśli wywołania metody ORM używają transakcji drobnoziarnistych (aktywne metody w stylu rekordu na przykład w jednostkach Spring Roo są domyślnie oznaczone jako @Transactional), operacje masowe będą powolne. Jeśli tak jest w twojej aplikacji, powinieneś przyjrzeć się logice transakcji.
  2. Buforowanie: w Hibernacji pamięć podręczna pierwszego poziomu pozwala menedżerowi jednostki uniknąć niepotrzebnych powrotów do bazy danych. Dobra rzecz ogólnie, ale zła w przypadku wstawiania zbiorczego, gdzie prowadzi do niepotrzebnego zatykania pamięci podręcznej, co powoduje obniżenie wydajności aplikacji. Jeśli to twój problem, powinieneś przyjrzeć się wzorowi grupowania sugerowanemu powyżej przez ChrisAnnODell. Używamy go u naszych importerów, co znacznie przyspiesza wkładki luzem.

Nie ma nic złego w korzystaniu z natywnego SQL w celu poprawy wydajności. Ale najpierw upewnij się, że rozumiesz, co cię spowalnia.

Wallenborn
źródło
Aby uniknąć bufora, użyj StatelessSession. Unikaj także identyfikatorów automatycznego przyrostu. Zamiast tego należy użyć HiLo lub Guid.
1

Omiń ORM. Nie tylko to, ale również ominąć „zwykły” sql. Użyj narzędzia zbiorczego bazy danych, aby wstawić bardzo duże zestawy danych do tabeli pomostowej. Następnie użyj sql do wykonania czynności związanych z inscenizacją.

Twoja ORM typu „smak bloga” może nie działać we wszystkich sytuacjach.

Lord Tydus
źródło
Tak, tego rodzaju narzędzia zaplecza są trudne do nauczenia się, ale po około 3 lub 4 razach będziesz ekspertem i możesz robić rzeczy szybciej, a czasem rzeczy, których nie da się zrobić w inny sposób. To jest jak różnica między łopatą a spychaczem. Napisałem narzędzia sterowane skryptami dla różnych platform do odczytu plików wejściowych tekstu i aktualizacji danych za pomocą operacji niskiego poziomu. Pisanie takiego narzędzia może również ułatwić Ci życie (lub przynajmniej bardziej interesujące). Takie rzeczy można wykorzystać do dostosowania danych dostosowywania instalacji klienta podczas aktualizacji oprogramowania.
0

Byłem w tej sytuacji. Czasami musisz.

Niektóre ORM pozwalają programistom pominąć model obiektowy i przejść bezpośrednio do warstwy bazy danych.

Istnieją również ORM, które wykorzystują operacje zbiorcze, enkapsulowane, jako obiektowe.

umlcat
źródło
0

Jak wspomniał Umlcat , istnieją pewne ORM, które pozwolą ci używać operacji masowych.

Co więcej, wiele ORM jest rozszerzalnych, więc możesz po prostu napisać własną metodę uruchamiania operacji masowych, jeśli nie jest już obsługiwana. Jeśli operacja zbiorcza w aplikacji jest czymś, co można oddzielić, dodam ją jako warstwę na ORM (aby to zrobić, prawdopodobnie będziesz musiał napisać surowy SQL), ale potem w aplikacji użyj ORM zaimplementowana metoda.

Ułatwia to także testowanie i debugowanie jednostek. Po uzyskaniu dobrego zasięgu testowego dla metod ORM możesz swobodnie używać go w swoich aplikacjach. W przeciwnym razie debugowanie surowego kodu SQL (szczególnie dużych z transakcjami i wieloma połączeniami) może być uciążliwe.

Raz zajęło mi prawie dzień, aby wykryć błąd w surowym wywołaniu SQL, który miał prawie 100 LOC, a błąd był tylko jedną postacią! Od tego czasu staram się unikać surowego SQL w aplikacji i wszystkie procedury SQL są osobno testowane jednostkowo.

Attila O.
źródło
0

Cóż, nie mam żadnych wzorów wzornictwa, o których jestem świadomy. Domyślam się, że podjąłeś decyzję o ORM z jakiegoś powodu, więc porzucenie ORM prawdopodobnie nie jest tym, czego chcesz. Jednak w tych przypadkach myślę, że jest miejsce na zmieszanie obu roztworów. Nie ma w tym nic złego, o ile robisz to świadomie i dokumentujesz, dlaczego odstępujesz od domyślnego użycia ORM w twoim oprogramowaniu. Oprócz tego niektóre frameworki ORM mają pewne funkcje do wykonywania operacji masowych. Wiem, że nHibernate (ORM dla platformy .NET) tak zwane StatelessSessions, które mają znacznie mniejszy narzut, ale może to nadal nie dać ci wzrostu wydajności, którego szukasz. W takim przypadku wystarczy użyć surowego SQL.

Pieter
źródło