Как улучшить объемную вставку Entity Framework

У меня есть приложение, которое получает данные из нескольких сокетов, а затем записывает данные в БД.

В настоящее время я использую EF для этого. Я хотел бы знать, как я могу сделать его более эффективным.

Я прочитал, что делать объемную вставку быстрее, поэтому я только сохраняю изменения в БД каждые 500 экземпляров:

db.Logs_In.Add(tableItem);
 if (logBufferCounter++ > 500)
 {
 db.SaveChanges();
 logBufferCounter = 0;
 }

Теперь я профилировал приложение, и 74% работы выполняется с помощью функции: System.Data.Enitity.DbSet'1[System._Canon].Add

Есть ли лучший способ сделать вставку? Возможно, очередь в таблицеItems в список, а затем добавить весь список в контекст БД.

Или, может быть, я смотрю на все это неправильно, и я должен полностью избегать использования EntityFramework для этой более высокой производительности вставки? В настоящее время это шея бутылки в моем приложении, и если я смотрю на системные ресурсы, то SQL, похоже, даже не сдвинется с места на веки.

Итак, мои вопросы:

1: каким образом я мог бы получить самую эффективную/быструю вставку на несколько вставок

2: Если EF является приемлемым, как я могу улучшить свое решение?

Я использую SQL Server 2012 Enterprise Edition, входящие данные являются постоянным потоком, однако я могу позволить себе его буферировать, а затем делать объемную вставку, если это лучшее решение.

[РЕДАКТИРОВАТЬ]

Для дальнейшего объяснения сценария. У меня есть поток, который зацикливается на concurrentQueue, который удаляет элементы из этой очереди. Однако из-за того, что вставка db представляет собой горло бутылки. в очереди много тысяч записей, поэтому, если есть также метод Async или Parallel, в котором я мог бы использовать более одного потока для вставки.

1 ответ

Для сценариев, в которых задействовано большое количество вставок, я предпочитаю "буфер отдельно" (в памяти или список redis или что-то еще), затем в качестве пакетного задания (возможно, каждую минуту или каждые несколько минут) читайте список и используйте SqlBulkCopy для того, чтобы максимально эффективно SqlBulkCopy данные в базу данных. Чтобы помочь в этом, я использую метод ObjectReader.Create для fastmember, который предоставляет List (или любой IEnumerable) в качестве IDataReader который может быть SqlBulkCopy в SqlBulkCopy, SqlBulkCopy свойства T как логические столбцы в данных ридер. Все, что вам нужно сделать, это заполнить List из буфера.

Обратите внимание, однако, что вам нужно подумать о сценарии "что-то не так"; т.е. если вставка не проходит на полпути, что вы делаете с данными в буфере? Один из вариантов состоит в том, чтобы сделать SqlBulkCopy в промежуточную таблицу (та же схема, но не в "живой" таблице), а затем использовать обычный INSERT для копирования данных за один шаг, когда вы знаете, что это в базе данных - это упрощает восстановление,

licensed under cc by-sa 3.0 with attribution.