Udostępnij za pośrednictwem


Wydajne aktualizowanie

Dzielenie na partie

Program EF Core pomaga zminimalizować przejazdy przez automatyczne dzielenie wszystkich aktualizacji w jedną rundę. Zaleca się uwzględnić następujące elementy:

var blog = context.Blogs.Single(b => b.Url == "http://someblog.microsoft.com");
blog.Url = "http://someotherblog.microsoft.com";
context.Add(new Blog { Url = "http://newblog1.microsoft.com" });
context.Add(new Blog { Url = "http://newblog2.microsoft.com" });
context.SaveChanges();

Powyższe ładuje blog z bazy danych, zmienia adres URL, a następnie dodaje dwa nowe blogi; aby to zastosować, do bazy danych są wysyłane dwie instrukcje SQL INSERT i jedna instrukcja UPDATE. Zamiast wysyłać je pojedynczo, ponieważ są dodawane wystąpienia blogów, program EF Core śledzi te zmiany wewnętrznie i wykonuje je w jednym węźle, gdy SaveChanges jest wywoływany.

Liczba instrukcji, które są wykonywane w partiach ef w ramach pojedynczej rundy, zależy od używanego dostawcy bazy danych. Na przykład analiza wydajności wykazała, że przetwarzanie wsadowe jest ogólnie mniej wydajne dla programu SQL Server, gdy są zaangażowane mniej niż 4 instrukcje. Podobnie korzyści wynikające z dzielenia na partie po około 40 instrukcjach dla programu SQL Server, dlatego program EF Core domyślnie będzie domyślnie wykonywać maksymalnie 42 instrukcje w jednej partii i wykonywać dodatkowe instrukcje w oddzielnych rundach.

Użytkownicy mogą również dostosować te progi, aby osiągnąć potencjalnie wyższą wydajność — ale należy dokładnie przeprowadzić test porównawczy przed zmodyfikowaniem następujących wartości:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(
        @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True",
        o => o
            .MinBatchSize(1)
            .MaxBatchSize(100));
}

Użyj polecenia ExecuteUpdate i ExecuteDelete, jeśli jest to istotne

Załóżmy, że chcesz dać wszystkim pracownikom podwyżkę. Typowa implementacja tej funkcji w programie EF Core wygląda następująco:

foreach (var employee in context.Employees)
{
    employee.Salary += 1000;
}
context.SaveChanges();

Chociaż jest to doskonale prawidłowy kod, przeanalizujmy to, co robi z perspektywy wydajności:

  • W celu załadowania wszystkich odpowiednich pracowników jest wykonywana dwukierunkowa baza danych; Należy pamiętać, że spowoduje to przeniesienie wszystkich danych wiersza pracowników do klienta, nawet jeśli będzie potrzebne tylko wynagrodzenie.
  • Śledzenie zmian platformy EF Core tworzy migawki podczas ładowania jednostek, a następnie porównuje te migawki z wystąpieniami, aby dowiedzieć się, które właściwości uległy zmianie.
  • Zazwyczaj jest wykonywana druga runda bazy danych w celu zapisania wszystkich zmian (należy pamiętać, że niektórzy dostawcy baz danych podzielili zmiany na wiele pasków). Mimo że takie zachowanie przetwarzania wsadowego jest znacznie lepsze niż wykonywanie w obie strony dla każdej aktualizacji, program EF Core nadal wysyła instrukcję UPDATE dla każdego pracownika, a baza danych musi wykonać każdą instrukcję oddzielnie.

Począwszy od programu EF Core 7.0, możesz użyć ExecuteUpdate metod i ExecuteDelete , aby wykonać to samo znacznie wydajniej:

context.Employees.ExecuteUpdate(s => s.SetProperty(e => e.Salary, e => e.Salary + 1000));

Spowoduje to wysłanie następującej instrukcji SQL do bazy danych:

UPDATE [Employees] SET [Salary] = [Salary] + 1000;

Spowoduje to UPDATE wykonanie całej operacji w jednym wędrze, bez ładowania ani wysyłania żadnych rzeczywistych danych do bazy danych oraz bez korzystania z maszyn śledzenia zmian ef, co nakłada dodatkowe obciążenie. Aby uzyskać więcej informacji, zobacz tematy ExecuteUpdate oraz ExecuteDelete.

Jeśli używasz starszej wersji programu EF Core, która nie obsługuje ExecuteUpdate jeszcze programu i ExecuteDelete, lub chcesz wykonać złożoną instrukcję SQL, która nie jest obsługiwana przez te metody, nadal możesz użyć zapytania SQL do wykonania operacji:

context.Database.ExecuteSql($"UPDATE [Employees] SET [Salary] = [Salary] + 1000");

Aby dowiedzieć się więcej o różnicach między elementami SaveChanges i ExecuteUpdateExecuteDelete/, zobacz stronę Przegląd na temat zapisywania danych.