我的EF实体类看起来像:
public class DataPoint
{
public int DataPointId {get; set;}
public DateTime DateTime {get; set;}
public double Value {get; set;}
}
其中DataPointId
是PK,当时没有其他列被编入索引。
假设我们有一个DataPoints集合,必须将其添加到context.DataPoints
数据库表中:
var dpToAdd = new List<DataPoint>{ /* 10000 different dp's */ };
但是,我想在db中只保存DataPoint's
列DateTime
时唯一的DataPoint
列。
例如:dpToAdd中的DateTime = 01/01/2016 00:00:00
之一有context.DataPoints
- 如果DateTime
已包含具有相同context.DataPoints
值的DataPoint,则应忽略此点。
DateTime
表可以有100万条记录,并且在单个请求中可以收集10-50k条记录,需要在保存到db之前进行验证。
如何处理这样的过程以使性能最佳?
我的第一个问题是在DataPoints
列上创建一个索引,然后,对于即将添加的每个foreach (var dp in dpToAdd)
{
// with Any()
if !(context.DataPoints.Any(p => p.DateTime == dp.DateTime))
{
context.DataPoints.Add(dp);
}
// or with Contains()
if !(context.DataPoints.Select(p => p.DateTime).Contains(dp.DateTime))
{
context.DataPoints.Add(dp);
}
}
,请检查以下内容:
1:简单地循环遍历所有积分并检查需要添加的内容
DateTime
2:获取已在数据库中出现的var common = context.DataPoints.Select(p => p.DateTime).Intersect(dpToAdd.Select(d => d.DateTime));
var reallyToAdd = dpToAdd.Where(p => !common.Contains(p.DateTime));
context.DataPoints.AddRange(reallyToAdd);
值,并将其从db addition
conda update conda
如果可以通过任何其他更好的方式开发此任务,您还有其他任何建议吗?
答案 0 :(得分:1)
如果您确实要插入如此大的表和大数据,出于性能原因,您应该使用相同的列加DataPointHelper
创建帮助中间表Guid
。首先,您将向此表插入数据,然后从DataPoints
表中获取不存在的行,然后将它们插入DataPoints
。 事务性正确性需要Guid
属性:
var guid = Guid.NewGuid();
var data = dpToAdd.Select(x => new DataPointHelper
{
DateTime = x.DateTime,
Value = x.Value,
Guid = guid
}).ToList();
context.DataPointHelpers.AddRange(data);//it is better to use BulkInsert
context.SaveChanges();
var toInsert = (from x in context.DataPointHelpers
where x.Guid == guid
join y in context.DataPoints on x.DateTime equals y.DateTime into subs
from sub in subs.DefaultIfEmpty()
where sub == null
select x.DateTime).ToList();
if(toInsert.Count > 0)
{
var toInsertData = dpToAdd.Where(x => toInsert.Contains(x.DateTime)).ToList();
context.DataPoints.AddRange(toInsertData);
context.SaveChanges();
}
当然,您应该在两个表中为DateTime
属性创建唯一索引。
因此,您只有三次往返数据库而不是数千次,或者不执行where DateTime in (thousands values)
之类的查询,而且in
语句有限制。
答案 1 :(得分:-1)
我认为你可以使用它:
var dt = DateTime.Now;
var ls = new List<DataPoint>();
ls.Add(new DataPoint { DataPointId =1, Value = 1, DateTime = dt});
ls.Add(new DataPoint { DataPointId =2, Value = 2, DateTime = dt});
ls.Add(new DataPoint { DataPointId =1, Value = 1, DateTime = DateTime.Now.AddDays(1)});
var distincData = ls.GroupBy(l => l.DateTime).Select(g => g.First());