Сохранение больших объемов данных в базу данных используя entity framework

243
16 октября 2018, 08:30

Программа парсит через VK API пользователей (в среднем в 20-50 потоков) и создает записи в базе данных. У каждого пользователя в среднем 20 групп, 500 фотографий, 200 друзей. Я храню в разных таблицах записи о друзьях, группах, пользователях и фотографиях. Итого, чтобы сохранить 1го пользователя у меня уходит около 721 запросов на вставку в базу. В минуту это 200-300 пользователей- ~216 000 запросов на вставку в базу. Из за этого вызов context.SaveChanges() отнимает около 6-10 минут на выполнение.

Пробовал использовать пул контекстов - bulk insert, среднее время- 4-6 минут.

AutoDetectChangesEnabled = false; или context.AddRange() дают примерно те же результаты.

Единственное быстрое решение, к которому я пришел - бинарно сериализовывать данные пользователя и хранить их в byte[], чтобы на юзера было 4 запроса вставки. Это сократило время вызова context.SaveChanges() до 1.2 секунды. Но вместе с этим появилась закономерная проблема - чтобы изменить хоть что–то у пользователя, надо десериализовывать и сериализовывать все его данные.

Подскажите, какие существуют подходы сохранения больших объемов данных применимые в данном случае не используя сериализацию?

Answer 1
  1. Не нужно вызывать context.SaveChanges() на каждый чих.

    Вставить 1000 записей за 1 context.SaveChanges() быстрее, чем на каждую запись вызвать context.SaveChanges().

  2. Если у тебя присутсвует какая-то сложная логика, то лучше эту логику вынести в хранимую процедуру.

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

  4. Огромное кол-во индексов может тормозить встаку.

  5. Отказаться вообще от EF прии вставках и рулить этим делом через BulkCopy.

    Например, заливаешь все массово в какую-нибудь таблицу на сервере, затем JOB каждые 5 минут опрашивает эту таблицу и выполняет добавление информации по рабочим таблицам.

  6. Еще бы профайлером не помешало бы посмотреть запросы, который формирует EF.

    Может быть они не оптимальны и стоит пошаманить с LINQ.

Я бы посоветовал замерить заполнение БД через BulkCopy(Самый быстрый способ множественных вставок) и тогда ты получишь величину к которой ты должен стримиться и выше которой не прыгнешь, используя EF.

READ ALSO
Почему разнятся значения Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) в разных приложениях?

Почему разнятся значения Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) в разных приложениях?

Я пишу сервис, где мне необходимо получить папку AppData\RoamingПользуюсь следующей конструкцией Environment

214
Вставить текст в документ libreoffice writer с помощью C#

Вставить текст в документ libreoffice writer с помощью C#

Каким образом с помощью C# можно вставлять текст на поля (placeholder) в документ libreoffice writer? Где можно найти руководство? К сожалению, информацию...

161
wpf datagrid view раскрытие в дерево

wpf datagrid view раскрытие в дерево

надо сделать возможность развернуть в виде дерева, как на скрине

157
Навигация в UWP приложениях

Навигация в UWP приложениях

Допустим, у меня есть NavigationView с некоторым числом item-ов и Frame Как мне сделать так, чтобы менялось отображение только в Frame? В инете нашёл только...

218