/ / NHibernate pobiera buforowane wyniki zapytania, mimo że klauzula ORDER BY różni się - nhibernate, sql-order-by, query-cache

NHibernate pobiera wyniki zapytań z pamięci podręcznej, mimo że klauzula ORDER BY różni się - nhibernate, sql-order-by, query-cache

Widzę coś, co nazwałbym błędem w NHibernate z buforowaniem zapytań i klauzulami ORDER BY ...

Po uruchomieniu następującego zapytania ...

SELECT this_.Id          as y0_,
this_.Name        as y1_
FROM   Products this_
WHERE  this_.IsActive = 1
ORDER BY this_.IsPremium desc

... NHibernate z powodzeniem buforuje wyniki, jeśli mam włączone buforowanie zapytań i każę buforować to zapytanie (używając np. criteria.SetCacheable(true)).

Niestety, jak cudownie NHProf mówi mi, że NHibernate używa wyników zapytania w pamięci podręcznej również podczas uruchamiania tego zapytania:

SELECT this_.Id          as y0_,
this_.Name        as y1_
FROM   Products this_
WHERE  this_.IsActive = 1
ORDER BY this_.IsPremium desc,
this_.Name

Czy ktoś może wyjaśnić dlaczego lub wskazać mi dogłębną dokumentację na temat tej „funkcji”? Lub, jeszcze lepiej, czy ktoś ma rozwiązanie na problem?

Odpowiedzi:

0 dla odpowiedzi № 1

NHibernate używa buforowania pierwszego poziomu (implementowanego przez mapę tożsamości) do buforowania każdego obiektu, o który pytasz. NHibernate działa na pojedynczych jednostkach, nawet jeśli przeszukujesz listę obiektów.

Pozwól mi wyjaśnić kilka rzeczy:
pytasz, jeśli wykonasz to zapytanie i spróbujesz uzyskać encję o identyfikatorze 1:

session.get<SomeEntity>(1);

NHibernate sprawdzi pamięć podręczną, aby zobaczyć, czy tozawiera już identyfikator 1. Jeśli tak, buforowany obiekt zostanie zwrócony i nie uruchomi zapytania. jeśli nie, zapytanie zostanie wykonane po wybraniu rekordu, włóż go do pamięci podręcznej i zwróć do Ciebie. Jeśli ponownie wykonasz zapytanie, zostanie ono zapisane w pamięci podręcznej, a obiekt zostanie zwrócony bez nowego zapytania.

teraz, jeśli zapytasz taką listę:

session.QueryOver<SomeEntity>().List();

nhibernate nie wie, jakie będą identyfikatorypobrane, w ten sposób przeszukuje wszystkie rekordy i sprawdza wyniki względem pamięci podręcznej jeden po drugim, nawet jeśli zapytanie zostanie uruchomione dwukrotnie. Powiedzmy, że masz 2 rekordy (id 1 i 2) w bazie danych. Pobierasz je za pomocą zapytania, gdy pamięć podręczna jest nadal pusta. oba rekordy są pobierane, umieszczane w pamięci podręcznej i zwracane do Ciebie. teraz wstawiasz rekordy 3, 4 i 5, a gdy jesteś przy nim, zaktualizujesz również rekord 1. Teraz, jeśli ponownie uruchomisz zapytanie, odczyta wszystkie 5 rekordów, ale teraz również cache 3, 4 i 5. Otrzymasz listę z 5 obiektami, z których 3, 4, 5 to te właśnie przeczytane, ale zwracane są wersje 1 i 2 w pamięci podręcznej. nie otrzymasz zaktualizowanej wersji identyfikatora 1.

aby odpowiedzieć na twoje pytanie: zmiana kolejności według nie ma znaczenia. Twoje zapytanie spowoduje zestaw rekordów, które są sprawdzane względem bufora jeden po drugim, a jeśli jeden z nich już istnieje, ta buforowana wersja jest zwracana.

Rozwiązaniami problemów mogą być:

  • using session.Refresh (obj); jeśli wiesz, które zostały zaktualizowane.
  • eksmitować niektóre lub wszystkie podmioty z sesji (co oznacza, że ​​„zostaną one wyrzucone z pamięci podręcznej i mogą zostać ponownie wygenerowane za pomocą zapytania). Uwaga: jeśli je wyrzucisz, zmiany nie zostaną zapisane.
  • możesz użyć sesji bezstanowej, która - jak sugeruje nazwa bezstanowa - nie ma pamięci podręcznej.