Поделиться через


Эффективное обновление

Пакетная обработка

EF Core помогает свести к минимуму круглые цепочки путем автоматической пакетной обработки всех обновлений в одном цикле. В частности, необходимо принимать во внимание следующее:

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();

Приведенный выше блог загружается из базы данных, изменяет его URL-адрес, а затем добавляет два новых блога; Чтобы применить это, в базу данных отправляются две инструкции SQL INSERT и одна инструкция UPDATE. Вместо отправки их по одному, так как экземпляры блога добавляются, EF Core отслеживает эти изменения внутри системы и выполняет их в одном цикле при SaveChanges вызове.

Количество инструкций, которые пакеты EF в одном цикле зависят от используемого поставщика базы данных. Например, анализ производительности показал, что пакетная обработка обычно менее эффективна для SQL Server, если используются менее 4 инструкций. Аналогичным образом преимущества пакетной обработки ухудшаются после примерно 40 инструкций для SQL Server, поэтому EF Core по умолчанию будет выполнять только до 42 инструкций в одном пакете и выполнять дополнительные инструкции в отдельных раундах.

Пользователи также могут настраивать эти пороговые значения для достижения потенциально более высокой производительности, но тщательно тестировать перед изменением этих значений:

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

Использование ExecuteUpdate и ExecuteDelete при необходимости

Предположим, вы хотите дать всем сотрудникам повышение. Типичная реализация для этого в EF Core будет выглядеть следующим образом:

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

Хотя это совершенно допустимый код, давайте рассмотрим то, что он делает с точки зрения производительности:

  • Выполняется циклический обход базы данных для загрузки всех соответствующих сотрудников; Обратите внимание, что это приводит ко всем данным строки сотрудников клиенту, даже если потребуется только зарплата.
  • Отслеживание изменений EF Core создает моментальные снимки при загрузке сущностей, а затем сравнивает эти моментальные снимки с экземплярами, чтобы узнать, какие свойства изменились.
  • Как правило, для сохранения всех изменений выполняется повторный обход второй базы данных (обратите внимание, что некоторые поставщики баз данных разделяют изменения на несколько циклов). Хотя это поведение пакетной обработки гораздо лучше, чем выполнение круглой передачи для каждого обновления, EF Core по-прежнему отправляет инструкцию UPDATE на сотрудника, и база данных должна выполнять каждую инструкцию отдельно.

Начиная с EF Core 7.0, вы можете использовать ExecuteUpdate и ExecuteDelete методы, чтобы сделать то же самое гораздо эффективнее:

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

При этом в базу данных отправляется следующая инструкция SQL:

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

Это UPDATE выполняет всю операцию в одном цикле без загрузки или отправки фактических данных в базу данных и без использования механизма отслеживания изменений EF, что приводит к дополнительным издержкам. Дополнительные сведения см. в разделах ExecuteUpdate и ExecuteDelete.

Если вы используете более раннюю версию EF Core, которая еще не поддерживается ExecuteUpdate и ExecuteDeleteне хотите выполнять сложную инструкцию SQL, которая не поддерживается этими методами, вы по-прежнему можете использовать SQL-запрос для выполнения операции:

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

Дополнительные сведения о различиях между SaveChanges ними ExecuteUpdateExecuteDelete/см. на странице "Обзор" по сохранению данных.