C # EF 5.0 Добавление миллионов записей в базу данных MySQL занимает несколько часов - PullRequest
0 голосов
/ 05 декабря 2018

Ниже приведен код, который я использую для добавления записей в базу данных. Я знаю, что я каждый раз вызываю saveChanges (), что дорого, но если сохранение вызова меняется один раз, я могу получить исключение повторяющегося ключа.Поэтому я ищу любую идею, чтобы улучшить производительность, помня о дублирующих записях.

using (var db = new dbEntities())
{

    for (int i = 0; i < csvCustomers.Count; i++)
    {
        var csvCustomer = csvCustomers[i];
        dbcustomer customer = new dbcustomer() { ADDRESS = csvCustomer.ADDRESS, FIRSTNAME = csvCustomer.FIRSTNAME, LASTNAME = csvCustomer.LASTNAME, PHONE = csvCustomer.PHONE, ZIPCODE = csvCustomer.ZIP };
        try
        {
            dbzipcode z = db.dbzipcodes.FirstOrDefault(x => x.ZIP == customer.ZIPCODE);
            //TODO: Handle if Zip Code not Found in DB
            if (z == null)
            {
                db.dbcustomers.Add(customer);
                throw new DbEntityValidationException("Zip code not found in database.");
            }
            customer.dbzipcode = z;
            z.dbcustomers.Add(customer);
            db.SaveChanges();
        }
    }
}

Одно из решений, которое я имею в виду, - добавить данные в пакетном режиме, а затем вызвать db.SaveChanges () и в случае исключения рекурсивно уменьшает размер пакета для этих записей.

1 Ответ

0 голосов
/ 06 декабря 2018

Использование EF для вставки огромных # записей повлечет за собой значительные затраты по сравнению с более прямыми подходами, но есть несколько соображений, которые можно сделать, чтобы заметно улучшить производительность.

Во-первых, пакетная обработказапросы с изменениями сохранения будут предпочтительнее сохранения отдельных записей или попытки зафиксировать все изменения сразу.Вам придется иметь дело с исключениями, если / когда пакет не удается.(Возможно, отправляя этот пакет по одной за раз, чтобы полностью изолировать дублирующиеся строки)

Далее вы можете предварительно кэшировать ваши почтовые индексы, а не просматривать их каждую итерацию.Не загружайте всю сущность, просто кешируйте почтовый индекс и идентификатор в список в памяти: (Если сущность почтового индекса составляет чуть больше, чем просто, просто загрузите сущность) var zipCodes = db.dbzipcodes.Select(x => new {x.ZIPCODEID, x.ZIP}). ToList ();

Это потребует некоторого дополнительного внимания, когда речь идет о назначении почтового индекса клиенту в пакетных вызовах, посколькуПочтовый индекс изначально не будет известен DbContext, но может быть известен, когда добавлен второй клиент с тем же почтовым индексом.

Чтобы связать почтовый индекс без загрузки его в DbContext:

var customerZipCode = zipCodes.SingleOrDefault(x => x.ZIP = customer.ZIPCODE);
// + exists check...
var zipCode = new dbzipcode { ZIPCODEID = customerZipCode.ZIPCODEID };
db.dbzipcodes.Attach(zipCode);
customer.dbzipcode = zipCode;
// ...

Если вы загрузили весь объект почтового индекса в кэшированный список, то var zipCode = new dbzipcode ... не требуется,просто прикрепите кешированную сущность.

Однако, если в пакете этот почтовый индекс уже был связан с DbContext, вы получите ошибку (независимо от того, кэшировали ли вы сущность или просто ID / код), таквам нужно сначала проверить почтовые индексы dbContext в памяти:

var customerZipCode = zipCodes.SingleOrDefault(x => x.ZIP = customer.ZIPCODE);
// + exists check...
var zipCode = db.dbzipcodes.Local.SingleOrDefault(x => x.ZIPCODEID == customerZipCode.ZIPCODEID) 
  ?? new dbzipcode { ZIPCODEID = customerZipCode.ZIPCODEID };
db.dbzipcodes.Attach(zipCode);
customer.dbzipcode = zipCode;
// ...

Наконец, EF отслеживает много дополнительной информации в памяти в качестве контекста, поэтому другим соображением наряду с пакетной обработкой было бы избегать использования того же самогоDbContext во всех пакетах, скорее, открывая DbContext для каждого пакета.Когда вы добавляете элементы и вызываете SaveChanges через DbContext, он все еще отслеживает каждую добавляемую сущность.Если вы делаете пакеты по 1000 штук или около того, контекст будет отслеживать только эту 1000, а не 1000, а затем 2000, затем 3000 и т. Д. До 5 миллионов строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...