Массовая Вставка в C# и EF Core. Начало
Независимо от того, создаёте ли вы платформу анализа данных, переносите устаревшую систему или привлекаете новых пользователей, вероятно, наступит момент, когда вам потребуется вставить огромный объём данных в БД. Традиционные методы слишком медленные. Поэтому необходимо понимание методов быстрой массовой вставки в C#. Сегодня рассмотрим несколько вариантов.
Примечание: Мы не будем рассматривать некоторые крайние варианты, вроде ручной генерации SQL запросов или использования параметров, возвращающих табличные значения (Table-Valued parameters).
Допустим, нам нужно вставить множество экземпляров класса User в соответствующую таблицу БД.
1. Простой (плохой) пример EF Core
Для сравнения рассмотрим простейший (плохой) вариант, где пользователи добавляются по одному:
using var ctx = new AppDbContext();
foreach (var u in GetUsers())
{
ctx.Users.Add(u);
await ctx.SaveChangesAsync();
}
Результаты ужасные (как и ожидалось из-за множества запросов в БД):
100 пользователей - 20 мс,
1000 – 260 мс,
10000 – 8,86 с.
Большее количество проверять бессмысленно, они занимают слишком много времени. Возьмём это за пример, как не надо делать массовую вставку.
*Заметьте, что время приведено только для сравнения между вариантами.
2. Добавление всех и сохранение в EF Core
Можно поправить пример выше, сначала добавив все записи в контекст, а затем 1 раз вызвав SaveChanges().
…
foreach (var u in GetUsers())
context.Users.Add(u);
await ctx.SaveChangesAsync();
Результаты:
100 - 2 мс,
1000 - 18 мс,
10000 - 203 мс,
100000 - 2,13 с,
1000000 - 21,56 с.
3. AddRange в EF Core
Мы можем добавить в контекст сразу всю коллекцию, используя метод AddRange:
…
ctx.Users.AddRange(GetUsers());
await context.SaveChangesAsync();
Результаты аналогичны примеру выше, но код короче.
4. EF Core Bulk Extensions
Библиотеку EF Core Bulk Extensions можно использовать для повышения производительности. Кстати, она позволяет делать не только массовую вставку. Библиотека с открытым кодом, но платная для коммерческого использования. Для нашего варианта подойдёт метод BulkInsertAsync:
…
await context.BulkInsertAsync(GetUsers());
Результаты впечатляющие:
100 - 1.9 мс,
1000 - 8 мс,
10000 - 76 мс,
100000 - 742 мс,
1000000 - 8,3 с.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/fast-sql-bulk-inserts-with-csharp-and-ef-core