@EDIT Я выполнил шаги из Самый быстрый способ вставки в Entity Framework и получил еще худшие результаты, так что это не дубликат.
Моя цель — создать начальный метод для заполнения одной из таблиц LocalDb. Метод добавит 182 500 строк (для имитации годовых данных об активности для 500 устройств) для дальнейшего тестирования. Возможно, я захочу запустить его еще несколько раз, чтобы изменить количество устройств, чтобы было сгенерировано еще больше строк. Вот почему мне нужно вставлять строки как можно эффективнее.
protected void SeedReportDataTable(int numberOfTerminals)
{
var rand = new Random();
var tidsList = new List<string>();
// generuj liste losowych numerow tid
for (int i = 0; i < numberOfTerminals; i++)
{
var randomTid = rand.Next(100000, 1000000).ToString(); // generuj 6-cyfrowy numer tid
while (tidsList.Contains(randomTid)) { randomTid = rand.Next(100000, 1000000).ToString(); } // elminuj powtorzenia
tidsList.Add(randomTid);
}
// dla kazdego z numerow tid generuj roczna historie aktywnosci
var recordsList = new BlockingCollection<ReportData>();
int year = Convert.ToInt32(DateTime.Now.Year);
Parallel.ForEach(tidsList, tid =>
{
// dla kazdego miesiaca
for (int month = 1; month <= 12; month++)
{
// dla kazdego dnia
for (int day = 1; day <= DateTime.DaysInMonth(year, month); day++)
{
var record = new ReportData
{
Tid = tid,
Active = Convert.ToBoolean(
rand.Next(0, 11)), // generuj losowy stan aktywnosci z prawdopodbienstwem 1/10 na bycie nieaktywnym
Date = new DateTime(year, month, day)
};
recordsList.Add(record);
}
}
});
// dodaj unikalne klucze glowne rekordom przed dodaniem do kontekstu bazy
var keyValue = 1;
foreach (var record in recordsList)
{
record.Id = keyValue++;
}
// podziel liste na czesci
int chunkSize = 1000;
for (int recordsSkipped = 0; recordsSkipped < recordsList.Count; recordsSkipped += chunkSize)
{
// wymieniaj kontekst
using (var db = new dbEntities())
{
db.Configuration.AutoDetectChangesEnabled = false;
db.Configuration.ValidateOnSaveEnabled = false;
// dodawaj do bazy po kawalku
db.ReportData.AddRange(recordsList.Skip(recordsSkipped).Take(chunkSize));
db.SaveChanges();
}
}
}
Выполнение этого кода заняло 30 минут. До этого я запускал версию, заканчивающуюся на:
using (var db = new dbEntities())
{
db.ReportData.AddRange(recordsList);
db.SaveChanges();
}
и это заняло 15 минут, что все же медленнее, чем я ожидал.
Почему мои "улучшения" не увенчались успехом?
Что я могу сделать, чтобы он вставлял строки быстрее?
It is not a duplicate because I followed tips from that topic and got even worse results
Можете ли вы показать нам версию кода, который вы протестировали с помощьюSqlBulkCopy
(и рассказать нам, сколько времени потребовалось для его выполнения)? - person mjwills   schedule 26.08.2017SqlBulkCopy
не имеет ничего общего с решением Entity Framework (не зависящим от базы данных). Которого к сожалению нет :( - person Ivan Stoev   schedule 26.08.2017recordsList.Skip(...).Take(...)
в цикле займет больше времени, чем больше элементов будет пропущено перед взятием. Вам нужно использовать другую структуру данных для Skip/Take или использовать другой подход к фрагментации. - person grek40   schedule 26.08.2017I would have to convert my list to datatable.
stackoverflow.com/questions/3913371/sqlbulkcopy-from-a-list - person mjwills   schedule 26.08.2017