我继承了设计糟糕的数据库表(没有主键或索引,超大nvarchar
字段,日期存储为nvarchar
等)。该表有大约350,000条记录。我按预定义的间隔递交了大约2,000个可能的新记录列表,如果数据库还没有匹配的记录,我必须插入任何可能的新记录。
我最初尝试在foreach
循环中进行比较,但很快就会发现可能有一种更有效的方法。在做了一些研究之后,我尝试了.Any()
,.Contains()
和.Exclude()
方法。
我的研究让我相信.Exclude()
方法效率最高,但在尝试时会出现内存错误。 .Any()
和.Contains()
方法似乎都需要大致相同的时间才能完成(比foreach
循环更快)。
两个列表的结构相同,每个列表包含多个字符串。如果你不介意的话,我有几个我没有找到满意答案的问题。
.Exclude()
方法被认为是最有效的吗?使用.Exclude()方法时有没有办法使用投影?我想找到一种方法可以实现:
List<Data> storedData = db.Data;
List<Data> incomingData = someDataPreviouslyParsed;
// No Projection that runs out of memory
var newData = incomingData.Exclude(storedData).ToList();
// PsudoCode that I would like to figure out if is possible
// First use projection on db so as to not get a bunch of irrelevant data
List<Data> storedData = db.Data.Select(x => new { x.field1, x.field2, x.field3 });
var newData = incomingData.Select(x => new { x.field1, x.field2, x.field3 }).Exclude(storedData).ToList();
在SQL Server Studio Manager中使用原始SQL语句,查询时间略长于10秒。使用EF,似乎需要超过一分钟。这是EF的优化不当的SQL,还是来自EF的开销会产生这样的差异?
半题外话:
从数据库中获取数据并将其存储在变量storedData
中时,是否会消除表中存储的任何索引(如果有的话)的用处?
我讨厌提出这么多问题,而且我确信很多(如果不是全部的话)都是非常无趣的。但是,我无处可去,我一整天都在寻找明确的答案。非常感谢任何帮助。
更新
经过进一步研究,我发现这个问题似乎是一个非常好的解决方案。使用EF,我从数据库中获取350,000条记录,只保留创建唯一记录所需的列。然后我获取该数据并将其转换为将保留列作为键的字典(如可以看到here)。这解决了返回数据中已经存在重复的问题,并且给了我一些快速的工作来比较我新解析的数据。性能提升非常明显!
我仍然不确定这是否接近最佳做法,但我当然可以忍受这种表现。我也看到了一些ToLookup()
的引用,我可能会尝试去看看那里是否有性能提升。不过,这里有一些代码来展示我的所作所为:
var storedDataDictionary = storedData.GroupBy(k => (k.Field1 + k.Field2 + k.Field3 + k.Field4)).ToDictionary(g => g.Key, g => g.First());
foreach (var item in parsedData)
{
if (storedDataDictionary.ContainsKey(item.Field1 + item.Field2 + item.Field3 + item.Field4))
{
// duplicateData is a previously defined list
duplicateData.Add(item);
}
else
{
// newData is a previously defined list
newData.Add(item);
}
}
答案 0 :(得分:0)
没有理由使用EF。
如果您要更新或插入记录(那些代表缺少“主键”的记录),则只抓取您决定所需的列。不要浪费其他列的记忆。
构建现有主键的HashSet(即,如果主键是数字,则为HashSet of int,如果它有多个键 - 将它们组合成字符串)。
检查你的2000项对抗HashSet,这非常快。
使用原始sql更新或插入项目。
答案 1 :(得分:0)
我建议你考虑用SQL做,而不是C#。你没有说你正在使用什么RDBMS,但你可以查看MERGE语句,例如(对于SQL Server 2008): https://technet.microsoft.com/en-us/library/bb522522%28v=sql.105%29.aspx
从广义上讲,该语句会检查记录是否为“新” - 如果是,则可以将其插入;如果没有UPDATE和DELETE功能,或者你只是忽略它。