2010-01-27 10 views
6

Mój problem polega na tym, że NHibernate staje się wykładniczo wolny podczas pobierania rekordów z bazy danych. Miałem wniosek, aby zasadniczo wyciągnąć wszystkie dane z bardzo dużej bazy danych do wykorzystania w raporcie.Wybór NHibernate rośnie wykładniczo powoli

Pomyślałem, że skoro nie mogę uzyskać wszystkich rekordów w jednym ujęciu, ponieważ zestaw rekordów jest tak duży, pomyślałem, że spróbuję go zepsuć. Zasadniczo I itating przez zakresy indeksu, tj. zapisuje id x do y, następnie y + 1 do z, i tak dalej.

Każdy zestaw wyników wynosi około 10megs. Pierwsze 20 lub mniej ciągnięć zajmuje mniej niż minutę, a po następnym pociągnięciu zajmuje to 10 minut, potem 30 minut i 1 godzinę. Zatrzymałem tam program, nie chciałem czekać, aż nadejdzie następne pociągnięcie. Uruchomiłem program ponownie, zaczynając od indeksu, w którym przerwałam, ponownie, pierwsze 20 lub tak ciągnie są naprawdę szybkie, a następnie z jakiegoś dziwnego powodu następuje poważne spowolnienie.

Każda pomoc zostanie bardzo doceniona.

Odpowiedz

8

NHibernate wykonuje dla Ciebie dużo pracy, co może spowolnić proces. Utrzymuje obiekty, z których wyciągnąłeś w sesji, czyli w zasadzie pamięć podręczną pierwszego poziomu. Po uruchomieniu zapytań sprawdzi to zestaw obiektów, aby zobaczyć, czy należy je ponownie przepuścić z powrotem do bazy danych (być może zmieniłeś je, aby teraz zostały zakwalifikowane jako wynik zapytania!). Tak więc jedną wielką możliwością jest to, że twoje zapytanie potajemnie przechodzi przez ogromną liczbę obiektów, próbując dowiedzieć się, co powinno być zapisane w bazie danych, zanim kiedykolwiek wyśle ​​zapytanie do bazy danych.

W takim przypadku można wypróbować sesję okresową. Usunąć() lub session.Evict (obiekt), która usuwa obiekty z pamięci podręcznej, tak aby NH nie próbowało uczynić bazy danych spójną z nimi. Zawsze możesz ponownie podłączyć obiekty, jeśli chcesz, aby NH "zwracał na nie uwagę".

Edytuj: lub użyj sesji bezstanowej. Oto example.

+6

Zgadzam się - sesja NHibernate staje się wolniejsza i wolniejsza, ponieważ pamięć podręczna pierwszego poziomu rośnie i rośnie. Innym sposobem rozwiązania tej sytuacji jest użycie "bezpaństwowej" sesji NHibernate, która w ogóle nie korzysta z pamięci podręcznej. Jest idealny do robienia operacji masowego przesyłania danych w ten sposób. –

+0

Tak, sesja nie jest przeznaczona do przechowywania tak wielu elementów. Doświadczyłem również tego rodzaju poważnego spowolnienia. Zgadzam się z Danielem na temat wykorzystania sesji bezpaństwowej w tym przypadku. –

+0

Dziękuję całej grupie, jesteście ratownicy życia. Użyłem sesji bezstanowej i teraz każde pociągnięcie zajmuje tyle samo czasu. – Bernard

1

Istnieje kilka sposobów, aby zwiększyć wydajność NHiberante

  • Drugi poziom cache
  • zachłanne ładowanie zapobiec wybierz N + 1
  • Kilka sposobów, aby wycisnąć wydajność z mapowania
  • Modyfikowanie indeksów bazy danych

Kiedy trwa tak długo, jak opisujesz, nie sądzę żadnych rzeczy opisane powyżej będą działały wystarczająco dobrze dla ciebie.

NHibernate nie jest przeznaczony do dużych zbiorów danych. NHibernate jest przydatny w przypadku większości zapytań używanych w aplikacji, szczególnie w przypadku zapytań, które mają niewiele więcej wyników niż prezentowane użytkownikowi na jednym ekranie. Jeśli chcesz użyć większych zestawów danych w niektórych częściach aplikacji, każda niewielka kara za wydajność spowodowana użyciem dowolnego narzędzia może stać się znacząca, gdy zbiór danych się zwiększy. Maksymalna wydajność może (niestety) osiągnąć tylko przez zwykły sql.

1

Bardzo prawdopodobną przyczyną jest brak indeksów. Zaproponuj, aby opublikować zapytanie, definicję tabeli i bieżące indeksy na tych tabelach.

Do celów raportowania może być konieczne utworzenie procedury składowanej (ewentualnie nawet widoku indeksowanego, jeśli dotyczy to dużej agregacji) i zawijanie go przy pomocy NHibernate.

Zapaliłbym również program SQL Profiler, aby zobaczyć, jakie zapytania są wykonywane.

Interesujący ?: Optimizing Performance in NHibernate

+0

+1 dla indeksów, z pewnością może tak być. Łatwe do przetestowania z niektórymi staromodnymi SQL –

3

Jako opcję można spróbować użyć StatelessSession. Nie będzie śledzić wszystkich wyciągniętych obiektów i nie spowolni twojej aplikacji