Dlaczego DbSet.Dodać pracę tak wolno?

Ten sam temat był omawiany tutaj 8 miesięcy temu: Jak przyspieszyć DbSet.Add()?. Nie zaproponowano innego rozwiązania niż użycie SqlBulkCopy, które nie jest dla nas akceptowalne. Postanowiłem poruszyć ten temat po raz kolejny, mając nadzieję, że pojawią się nowe przemyślenia i pomysły dotyczące tego problemu i zaproponowane zostaną inne obejścia. Przynajmniej jestem ciekaw, dlaczego ta operacja trwa tak długo.

Problem w tym, że muszę zaktualizować 30K encji do bazy danych (EF 4.1, POCO). Na Typ entity jest dość prosty zawierający integer Id + inne 4 właściwości integer bez relacji do innych typów. 2 przypadki:
  • Wszystkie są nowymi płytami. Uruchamianie kontekstu./ Align = "left" / Dodawanie (encji) jeden po drugim dla każdego encji zajmuje 90 sekund z Cntx.Konfiguracja.AutoDetectChangesEnabled = false(wartość true powoduje, że działa w nieskończoność). Wtedy SaveChanges zajmuje tylko sekundę. Inne podejście: dołączenie go do kontekstu w ten sposób zajmuje to samo 90 sek:
    Cntx.Entities.Attach(entity);
    Cntx.Entry(entity).State = EntityState.Added;
    
  • Wszystkie są istniejące rekordy z pewnymi zmianami. W przypadku, gdy dołączenie go do istniejącego kontekstu danych zajmuje zaledwie kilka milisekund w następujący sposób:

    Cntx.Entities.Attach(entity);
    Cntx.Entry(entity).State = EntityState.Modified;
    
    Widzisz różnicę?

Co kryje się za sceną metody dodawania, która sprawia, że działa ona tak niewiarygodnie wolno?

Author: Community, 2011-08-13

1 answers

Mam ciekawe wyniki testów wydajności i znalazłem winowajcę. Nie widziałem takiej informacji w żadnym źródle EF, jakie kiedykolwiek czytałem.

Okazuje się, że jest równa overridden w klasie bazowej. Klasa bazowa powinna zawierać właściwość Id współdzieloną między wszystkimi typami konkretnych encji. Takie podejście zalecane przez wiele książek EF i dość dobrze wiem. Można go znaleźć tutaj na przykład: Jak najlepiej zaimplementować równe dla typów niestandardowych?

Dokładniej, wydajność jest zabijana przez unboxing operacji (obiekt do konwersji typu betonu), która sprawiła, że działa tak wolno. Jak skomentowałem tą linijkę kodu to zajęło 3 sek aby uruchomić do 90 sek wcześniej!

public override bool Equals ( object obj )
{
    // This line of code made the code so slow 
    var entityBase = obj as EntityBase;
    ...
}

Gdy go znalazłem, zacząłem zastanawiać się, co może być alternatywą dla tego równania. Pierwszym pomysłem było zaimplementowanie IEquatable dla EntityBase, ale okazało się, że w ogóle nie został uruchomiony. Postanowiłem więc w końcu zaimplementować IEquatable dla każdej konkretnej klasy entity w moim modelu. Mam tylko kilka z nich, więc jest to dla mnie drobna aktualizacja. Możesz umieścić całą funkcjonalność operacji Equal (zwykle jest to porównanie 2 ID obiektów) w metodzie rozszerzenia, aby współdzielić między konkretnymi klasami encji i uruchomić ją w następujący sposób: Equal ((EntityBase)ConcreteEntityClass). Najciekawsze, to IEquatable przyspiesza EntitySet.Dodaj 6 razy!

Więc nie mam więcej problemów z wydajnością, ten sam kod działa dla mnie z mniej niż sekundę. Mam 180 razy wzrost wydajności! Niesamowite!

Wniosek :

  1. najszybszy sposób na uruchomienie EntitySet.W tym celu należy dodać IEquatable dla określonego podmiotu (0.5 sec)
  2. Brak IEquatable sprawia, że działa 3 sek.
  3. posiadanie równych (object obj), które większość źródeł zaleca, sprawia, że działa 90 sek
 27
Author: YMC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:08:03