Entity Framework Улучшение производительности EF DetectChanges
Как улучшить производительность Entity Framework DetectChanges?
Когда вы отслеживаете несколько объектов в своем контексте, ваше приложение будет страдать от проблем с производительностью, вызванных методом Entity Framework DetectChanges.
using (var ctx = new CustomerContext())
{
foreach(var line in lines)
{
var customer = new Customer();
// ...code...
// DetectChanges is invoked every time you call Add
ctx.Customers.Add(customer);
}
ctx.SaveChanges();
}
StackOverflow Вопросы, связанные с
Ответ
- УМЕНЬШИТЬ количество сущностей в вашем контексте
- Сократите количество DetectChanges
- УСТАНОВИТЬ AutoDetectChanges на false
УМЕНЬШИТЕ количество объектов в вашем контексте
При добавлении / изменении нескольких сущностей разбивайте свою логику на многочисленные партии, чтобы в контексте было меньше записей.
Зачем?
Чем больше сущностей отслеживания содержится в вашем контексте, тем медленнее метод DetectChanges!
Сравнение производительности
операции | 100 сущностей | 1000 сущностей | 10000 сущностей |
---|---|---|---|
неограниченный | 15 мс | 1050 мс | 105 000 мс |
10 | 3 мс | 40 мс | 350 мс |
100 | 15 мс | 125 мс | 1200 мс |
1000 | 15 мс | 1050 мс | 10 200 мс |
Замечания:
- * : Время сохранения не включено
- ** : сущность с двумя отношениями
Как?
- CREATE переменная batchSize
- CALL SaveChanges перед созданием новой партии
- ВЫЗОВ Сохранить
- Готово!
// 1. CREATE a batchSize variable
int batchSize = 400;
var context = new EntityContext();
for(int i = 0; i <= 2000; i++)
{
// 2. CALL SaveChanges before creating a new batch
if (i != 0 && i%batchSize == 0)
{
context.SaveChanges();
context = new EntityContext();
}
var customer = new Customer();
// ...code...
context.Customers.Add(customer);
}
// 3. CALL SaveChanges
context.SaveChanges();
// 4. Done!
Уменьшите количество DetectChanges
При добавлении нескольких сущностей, вы всегда должны использовать Entity Framework AddRange один раз со списком, а не вызывать разный метод Add.
Зачем?
- Метод Add DetectChanges после каждой добавленной записи.
- Метод AddRange DetectChanges после добавления всех записей.
Сравнение производительности
операции | 100 сущностей | 1000 сущностей | 10000 сущностей |
---|---|---|---|
добавлять | 15 мс | 1050 мс | 105 000 мс |
AddRange | 1 мс | 10 мс | 120 мс |
Замечания:
- * : Время сохранения не включено
- ** : сущность с двумя отношениями
Как?
- СОЗДАТЬ список
- ДОБАВИТЬ сущность в список
- ИСПОЛЬЗОВАТЬ AddRange со списком
- Сохранить изменения
- Готово!
using (var context = new EntityContext())
{
// 1. CREATE a list
List<Customer> list = new List<Customer>();
for(int i = 0; i < 2000; i++)
{
var customer = new Customer();
// ...code...
// 2. ADD entity to the list
list.Add(customer);
}
// 3. USE AddRange with the list
context.Customers.AddRange(list);
// 4. SaveChanges
ctx.SaveChanges();
// 5. Done!
}
УСТАНОВИТЬ AutoDetectChanges на false
При добавлении нескольких объектов, если вы не можете использовать AddRange, установите для Entity Framework AutoDetectChanges значение false
Зачем?
- Метод Add DetectChanges после каждой добавленной записи.
При отключении AutoDetectChanges метод DetectChanges будет вызываться только тогда, когда вы это сделаете.
Сравнение производительности
операции | 100 сущностей | 1000 сущностей | 10000 сущностей |
---|---|---|---|
True (по умолчанию) | 15 мс | 1050 мс | 105 000 мс |
Ложь | 1 мс | 14 мс | 180 мс |
Замечания:
- * : Время сохранения не включено
- ** : сущность с двумя отношениями
Как?
- SET AutoDetectChangesEnabled = false
- CALL DetectChanges перед SaveChanges
- Сохранить изменения
- Готово!
using (var context = new EntityContext())
{
// 1. SET AutoDetectChangesEnabled = false
context.Configuration.AutoDetectChangesEnabled = false;
List<Customer> list = new List<Customer>();
for(int i = 0; i < 2000; i++)
{
var customer = new Customer();
// ...code...
list.Add(customer);
}
context.Customers.AddRange(list);
// 2. CALL DetectChanges before SaveChanges
context.ChangeTracker.DetectChanges();
// 3. SaveChanges
context.SaveChanges();
// 4. Done!
}