Postępowałem zgodnie z mantrą „Don't Optimize Prematurely” i zakodowałem moją usługę WCF przy użyciu Entity Framework.
Jednak profilowałem wydajność i Entity Framework jest zbyt wolny. (Moja aplikacja przetwarza 2 wiadomości w około 1,2 sekundy, podczas gdy (starsza) aplikacja, którą piszę ponownie, wykonuje 5-6 wiadomości w tym samym czasie (starsza aplikacja wywołuje sprocy w celu uzyskania dostępu do bazy danych).
Moje profilowanie wskazuje, że Entity Framework zajmuje większość czasu na wiadomość.
Więc jakie mam opcje?
Czy są tam lepsze ORMy?
(Coś, co obsługuje tylko normalne czytanie i pisanie obiektów i robi to szybko ...)Czy istnieje sposób na przyspieszenie Entity Framework?
( Uwaga : kiedy mówię szybciej, mam na myśli na dłuższą metę, a nie pierwsze połączenie. (Pierwsze połączenie jest wolne (15 sekund na wiadomość), ale to nie jest problem. Po prostu potrzebuję, aby było szybkie dla reszty wiadomości.)Jakaś tajemnicza trzecia opcja, która pomoże mi przyspieszyć działanie moich usług.
UWAGA: Większość moich interakcji z bazą danych to tworzenie i aktualizacja. Robię bardzo mało zaznaczania i usuwania.
źródło
Odpowiedzi:
Należy rozpocząć od profilowania poleceń SQL faktycznie wydanych przez Entity Framework. W zależności od konfiguracji (POCO, jednostki Self-Tracking) jest dużo miejsca na optymalizacje. Możesz debugować polecenia SQL (które nie powinny różnić się między trybami debugowania i wydania) przy użyciu
ObjectSet<T>.ToTraceString()
metody. Jeśli napotkasz zapytanie, które wymaga dalszej optymalizacji, możesz użyć niektórych prognoz, aby przekazać EF więcej informacji o tym, co próbujesz osiągnąć.Przykład:
Product product = db.Products.SingleOrDefault(p => p.Id == 10); // executes SELECT * FROM Products WHERE Id = 10 ProductDto dto = new ProductDto(); foreach (Category category in product.Categories) // executes SELECT * FROM Categories WHERE ProductId = 10 { dto.Categories.Add(new CategoryDto { Name = category.Name }); }
Można zastąpić:
var query = from p in db.Products where p.Id == 10 select new { p.Name, Categories = from c in p.Categories select c.Name }; ProductDto dto = new ProductDto(); foreach (var categoryName in query.Single().Categories) // Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId { dto.Categories.Add(new CategoryDto { Name = categoryName }); }
Właśnie wpisałem to z głowy, więc nie jest to dokładnie sposób, w jaki zostałoby to wykonane, ale EF faktycznie wykonuje kilka fajnych optymalizacji, jeśli powiesz mu wszystko, co wiesz o zapytaniu (w tym przypadku będziemy potrzebować kategorii- nazwy). Ale to nie jest jak szybkie ładowanie (db.Products.Include ("Categories")), ponieważ prognozy mogą dodatkowo zmniejszyć ilość danych do załadowania.
źródło
Faktem jest, że produkty takie jak Entity Framework będą ZAWSZE powolne i nieefektywne, ponieważ wykonują dużo więcej kodu.
Uważam również za głupie, że ludzie sugerują, że należy zoptymalizować zapytania LINQ, spojrzeć na wygenerowany SQL, użyć debuggerów, prekompilować, wykonać wiele dodatkowych kroków itp., Tj. Marnować dużo czasu. Nikt nie mówi - Uprość! Każdy chce komplikować sprawy dalej, podejmując jeszcze więcej kroków (marnowanie czasu).
Zdrowym rozsądkiem byłoby w ogóle nie używać EF lub LINQ. Użyj zwykłego języka SQL. Nie ma w tym nic złego. To, że programiści mają mentalność stadną i czują potrzebę używania każdego nowego produktu, nie oznacza, że jest dobry lub zadziała. Większość programistów uważa, że jeśli włączą każdy nowy fragment kodu wydany przez dużą firmę, stanie się to mądrzejszym programistą; wcale nie jest prawdą. Inteligentne programowanie polega głównie na tym, jak zrobić więcej przy mniejszych bólach głowy, niepewności i jak najmniejszym czasie. Pamiętaj czas! To jest najważniejszy element, więc staraj się znaleźć sposób, aby nie marnować go na rozwiązywanie problemów w złym / rozdętym kodzie napisanym po prostu w celu dostosowania się do dziwnych tak zwanych `` wzorców ''
Zrelaksuj się, ciesz się życiem, zrób sobie przerwę od kodowania i przestań używać dodatkowych funkcji, kodu, produktów, „wzorców”. Życie jest krótkie, a czas życia twojego kodu jeszcze krótszy iz pewnością nie jest to fizyka jądrowa. Usuń warstwy, takie jak LINQ, EF i inne, a Twój kod będzie działał wydajnie, będzie skalowany i tak, nadal będzie łatwy w utrzymaniu. Zbyt dużo abstrakcji to zły „wzór”.
I to jest rozwiązanie Twojego problemu.
źródło
Jedną z sugestii jest użycie LINQ to Entity Framework tylko w przypadku instrukcji CRUD z jednym rekordem.
Aby uzyskać bardziej złożone zapytania, wyszukiwania, raportowanie itp., Napisz procedurę składowaną i dodaj ją do modelu Entity Framework zgodnie z opisem w witrynie MSDN .
To jest podejście, które zastosowałem w przypadku kilku moich witryn i wydaje się, że jest to dobry kompromis między produktywnością a wydajnością. Entity Framework nie zawsze generuje najbardziej wydajny kod SQL dla wykonywanego zadania. Zamiast tracić czas na zastanawianie się, dlaczego, pisanie procedury składowanej dla bardziej złożonych zapytań w rzeczywistości oszczędza mi czas. Po zapoznaniu się z procesem dodawanie przechowywanych procesów do modelu EF nie jest zbyt trudne. I oczywiście zaletą dodania go do modelu jest to, że otrzymujesz całą silnie wpisaną dobroć, która pochodzi z używania ORM.
źródło
Jeśli czysto pobierania danych, to duża pomoc do wykonywania kiedy powiesz EF nie śledzić podmiotów to pobierania. Zrób to za pomocą MergeOption.NoTracking. EF po prostu wygeneruje zapytanie, wykona je i deserializuje wyniki do obiektów, ale nie będzie próbować śledzić zmian jednostek ani niczego podobnego. Jeśli zapytanie jest proste (nie spędza dużo czasu na oczekiwaniu na zwrócenie bazy danych), stwierdziłem, że ustawienie go na NoTracking może podwoić wydajność zapytania.
Zobacz ten artykuł MSDN dotyczący wyliczenia MergeOption:
Rozpoznawanie tożsamości, zarządzanie stanem i śledzenie zmian
To wydaje się być dobrym artykułem na temat wydajności EF:
Wydajność i Entity Framework
źródło
Mówisz, że sprofilowałeś aplikację. Czy profilowałeś również ORM? Istnieje profiler EF firmy Ayende, który podświetli, gdzie można zoptymalizować kod EF. Znajdziesz go tutaj:
http://efprof.com/
Pamiętaj, że możesz użyć tradycyjnego podejścia SQL razem z ORM, jeśli chcesz zwiększyć wydajność.
Czy istnieje szybszy / lepszy ORM? W zależności od modelu obiektu / danych możesz rozważyć użycie jednego z mikro-ORMów, takich jak Dapper , Massive lub PetaPoco .
Witryna Dapper publikuje porównawcze testy porównawcze, które dadzą ci wyobrażenie, jak wypadają w porównaniu z innymi ORMami. Warto jednak zauważyć, że mikro-ORMy nie obsługują bogatego zestawu funkcji pełnych ORMów, takich jak EF i NH.
Możesz rzucić okiem na RavenDB . Jest to nierelacyjna baza danych (ponownie od Ayende), która umożliwia bezpośrednie przechowywanie POCO bez konieczności mapowania . RavenDB jest zoptymalizowany pod kątem odczytów i znacznie ułatwia życie programistom, eliminując potrzebę manipulowania schematem i mapowania obiektów na ten schemat. Należy jednak pamiętać, że jest to znacznie inne podejście do korzystania z podejścia ORM i są one opisane w witrynie produktu .
źródło
Uważam, że odpowiedź @Slauma jest tutaj bardzo przydatna do przyspieszenia działania. Użyłem tego samego wzoru zarówno dla wstawek, jak i aktualizacji - i wydajność wzrosła.
źródło
Z mojego doświadczenia wynika, że problem nie dotyczy EF, ale samego podejścia ORM.
Ogólnie rzecz biorąc, wszystkie ORM cierpią na problem N + 1 niezoptymalizowanych zapytań itp. Moim najlepszym przypuszczeniem byłoby wyśledzenie zapytań, które powodują spadek wydajności i próba dostrojenia narzędzia ORM lub przepisanie tych części za pomocą SPROC.
źródło
Jest to prosta opcja niezwiązana z platformą i ORM, która ładuje się z prędkością 10 000 / sekundę przy około 30 polach. Działa na starym laptopie, więc prawdopodobnie szybciej niż w prawdziwym środowisku.
https://sourceforge.net/projects/dopersistence/?source=directory
źródło
Natknąłem się również na ten problem. Nienawidzę zrzucać na EF, ponieważ działa tak dobrze, ale jest po prostu powolny. W większości przypadków po prostu chcę znaleźć rekord lub zaktualizować / wstawić. Nawet proste operacje, takie jak ta, są powolne. Wyciągnąłem 1100 rekordów z tabeli do listy i ta operacja trwała 6 sekund z EF. Dla mnie to za długo, nawet oszczędzanie trwa zbyt długo.
Skończyło się na stworzeniu własnego ORM. Wyciągnąłem te same 1100 rekordów z bazy danych i mój ORM zajął 2 sekundy, znacznie szybciej niż EF. Wszystko z moim ORM jest prawie natychmiastowe. Jedynym ograniczeniem w tej chwili jest to, że działa tylko z MS SQL Server, ale można go zmienić, aby działał z innymi, takimi jak Oracle. Obecnie używam MS SQL Server do wszystkiego.
Jeśli chcesz wypróbować mój ORM, tutaj znajduje się link i strona internetowa:
https://github.com/jdemeuse1204/OR-M-Data-Entities
Lub jeśli chcesz użyć samorodka:
PM> Install-Package OR-M_DataEntities
Dokumentacja jest tam również
źródło
Optymalizacja ma sens dopiero po profilowaniu. Jeśli okaże się, że dostęp do bazy danych jest powolny, możesz przekonwertować na użycie procedur składowanych i zachować EF. Jeśli okaże się, że to sam EF jest powolny, być może będziesz musiał przełączyć się na inny ORM lub w ogóle nie używać ORM.
źródło
Mamy podobną aplikację (Wcf -> EF -> database), która z łatwością wykonuje 120 żądań na sekundę, więc jestem więcej niż pewien, że EF nie jest tutaj twoim problemem, to powiedziawszy, widziałem znaczną poprawę wydajności w przypadku skompilowanych zapytań.
źródło
Użyłem EF, LINQ do SQL i eleganckiego. Najszybszy jest elegancki. Przykład: potrzebowałem 1000 głównych rekordów, z których każdy miał 4 podrzędne. Użyłem LINQ do sql, zajęło to około 6 sekund. Następnie przełączyłem się na dapper, odzyskałem 2 zestawy rekordów z pojedynczej procedury składowanej i dla każdego rekordu dodałem rekordy podrzędne. Całkowity czas 1 sekunda.
Również procedura składowana korzystała z funkcji wartości tabelarycznych z zastosowaniem krzyżowym. Okazało się, że funkcje wartości skalarnych są bardzo wolne.
Moją radą byłoby użycie EF lub LINQ to SQL i w pewnych sytuacjach przełączenie się na eleganckie.
źródło
Entity Framework nie powinien sam powodować głównych wąskich gardeł. Są szanse, że są inne przyczyny. Możesz spróbować przełączyć EF na Linq2SQL, oba mają funkcje porównawcze, a kod powinien być łatwy do konwersji, ale w wielu przypadkach Linq2SQL jest szybszy niż EF.
źródło