c# - FirstOrDefault() 为迭代添加天数
问题描述
这里有一种边缘案例问题。我的任务是将所有数据从一个数据库拉到另一个数据库,其中目标数据库具有不同的架构。
我选择编写一个 WinForms 实用程序来在必要时使用 Entity Framework/ADO.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 而不是迁移数据列表运行
FirstOrDefault()
,没有看到任何改进。 - 映射到列表而不是数据表,但这对映射速度没有影响,并且也会使批量保存速度变慢。
我一直在考虑将foreach
foreach 转换为并行 foreach 循环并锁定对数据表的调用,但我一直遇到
实体框架连接关闭问题
在使用并行 foreach 时查询内存列表时......不太确定那是什么,但最初的速度结果很有希望。
如果有人认为这是正确的道路,我很乐意发布该代码/错误,但我不确定了..
解决方案
我要尝试的第一件事是字典,并预取列:
var fk1 = oldDatasetInMemory.Columns["ForeignKeyColumn1"];
// ...
var alreadyMigratedTable1 = newModelContext.alreadyMigratedTable1.ToDictionary(
x => x.uniquePropertyOnNewDataset);
// ...
if (alreadyMigratedTable1.TryGetValue(masterData.uniquePropertyOnOldDataset, out var val))
row[fk1] = val;
DataTable
然而,在现实中:除非真的非常有必要,否则我也会尽量避免整篇文章。
推荐阅读
- r - 将长格式数据帧转换为宽格式 tidyverse
- reactjs - Typescript 显然为分派的 Thunk 推断出错误的类型
- javascript - 在 NextJS 中将自定义 JavaScript 插入到帖子页面的正确方法是什么?
- jwt - Keycloak 返回已经过期的令牌
- python - 生成随机数的 While 循环
- python - Convert a time range into a list
- python - 有效地将噪声添加到模型中的所有可训练权重
- google-bigquery - 通过 Google 表格修改 BQ 数据集
- django - Ajax,Django:状态 200 但抛出错误而不是成功
- javascript - React:[object Object] 通过选择/选项值传递