这里有一个边缘案件的问题。我的任务是将所有数据从一个数据库拉到另一个数据库,目标数据库有不同的模式。
我选择编写一个WinForms实用程序,在必要时使用Entity Framework/a do.NET进行数据映射和传输。
到目前为止,这项工作非常成功,除了这个有250万条记录的特定表。当我忽略所有外键时,传输总共大约10分钟,但是当我开始映射外键时
FirstOrDefault()
对已移动到目标数据库的内存中数据列表的调用,实际上是将4天添加到所需的时间中。
我需要在未来几天运行这个工具,所以这对我来说是不可接受的。
以下是我目前的方法(不是我的第一种方法,这是为了提高效率而反复尝试的结果):
private OldModelContext _oldModelContext { get; } //instantiated in controller
using (var newModelContext = new NewModelContext())
{
//Takes no time at all to load these into memory, collections are small, 3 - 20 records each
var alreadyMigratedTable1 = newModelContext.alreadyMigratedTable1.ToList();
var alreadyMigratedTable2 = newModelContext.alreadyMigratedTable2.ToList();
var alreadyMigratedTable3 = newModelContext.alreadyMigratedTable3.ToList();
var alreadyMigratedTable4 = newModelContext.alreadyMigratedTable4.ToList();
var alreadyMigratedTable5 = newModelContext.alreadyMigratedTable5.ToList();
var oldDatasetInMemory = _oldModelContext.MasterData.AsNoTracking().ToList();//2.5 Million records, takes about 6 minutes
var table = new DataTable("MasterData");
table.Columns.Add("Column1");
table.Columns.Add("Column2");
table.Columns.Add("Column3");
table.Columns.Add("ForeignKeyColumn1");
table.Columns.Add("ForeignKeyColumn2");
table.Columns.Add("ForeignKeyColumn3");
table.Columns.Add("ForeignKeyColumn4");
table.Columns.Add("ForeignKeyColumn5");
foreach(var masterData in oldDatasetInMemory){
DataRow row = table.NewRow();
//With just these properties mapped, this takes about 2 minutes for all 2.5 Million
row["Column1"] = masterData.Property1;
row["Column2"] = masterData.Property2;
row["Column3"] = masterData.Property3;
//With this mapping, we add about 4 days to the overall process.
row["ForeignKeyColumn1"] = alreadyMigratedTable1.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
row["ForeignKeyColumn2"] = alreadyMigratedTable2.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
row["ForeignKeyColumn3"] = alreadyMigratedTable3.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
row["ForeignKeyColumn4"] = alreadyMigratedTable4.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
row["ForeignKeyColumn5"] = alreadyMigratedTable5.FirstOrDefault(s => s.uniquePropertyOnNewDataset == masterData.uniquePropertyOnOldDataset);
table.Rows.Add(row);
}
//Save table with SQLBulkCopy is very fast, takes about a minute and a half.
}
}
注:
uniquePropertyOn(New/Old)Dataset
通常是在数据集之间共享的唯一描述字符串,无法匹配ID,因为它们在数据库中不相同。
我试过:
-
不是用foreach,而是用linq
select
声明,没有多少改进。
-
使用
.Where(predicate).FirstOrDefault()
,没有明显的改善
-
跑步
第一个默认值()
对于iqueryable而不是迁移数据的列表,没有看到任何改进。
-
映射到列表而不是数据表,但这不会影响映射速度,也会使大容量存储速度变慢。
我一直在胡思乱想
foreach
进入一个并行foreach循环并锁定对datatable的调用,但是
实体框架连接关闭问题
当使用parallel foreach查询内存中的列表时。。。。不太确定这是什么,但最初的速度结果是有希望的。
如果有人认为这条路是正确的,我很乐意发布代码/错误,但我不确定了。。