1

由于我的数据库的特殊设计结构,我在 EF 中的性能非常差。以下是相关关系:


ERD


我有以下数据模型:


public class Sensor
{
    [Key]
    public int Id { get; set; }

    [Required, MaxLength(64)]
    public string Name { get; set; }

    [Required, ForeignKey("Type")]
    public int SensorTypeId { get; set; }

    public virtual SensorType Type { get; set; }

    public virtual ICollection<SensorSample> SensorSamples { get; set; }
}

public class SensorSample
{
    [Key]
    public int Id { get; set; }

    [Required, ForeignKey("Sensor")]
    public int SensorId { get; set; }

    public virtual Sensor Sensor { get; set; }

    [Required]
    public DateTime SampleTime { get; set; }

    [Required]
    public virtual ICollection<SampleData> SampleData { get; set; }
}

public class SampleData
{
    [Key]
    public int Id { get; set; }

    [Required, ForeignKey("DataType")]
    public int SampleDataTypeId { get; set; }

    public virtual SampleDataType DataType { get; set; }

    [Required, ForeignKey("Unit")]
    public int SampleUnitId { get; set; }

    public virtual SampleUnit Unit { get; set; }

    [Required, ForeignKey("Sample")]
    public int SensorSampleId { get; set; }

    public virtual SensorSample Sample { get; set; }

    [MaxLength(128)]
    public string Value { get; set; }
}

因为 aSensorSample可以有多种数据样本类型(即温度、压力等),所以INSERT必须查询现有样本以与正确的SampleTime. 这是使用以下代码完成的:


SensorSample sample = null;
foreach (var d in input)
{
    SampleData data = new SampleData();
    data.SampleDataTypeId = dataTypeId;
    data.SampleUnitId = unitId;
    data.Value = d.Value;

    // check for existing sample for this sensor and timestamp
    sample = SensorSamples.FirstOrDefault(s => s.SensorId == sensor.Id && s.SampleTime == d.Timestamp);
    if (sample == null)
    {
        // sample doesn't exist, create a new one
        sample = new SensorSample();
        sample.SampleTime = d.Timestamp;
        sample.SensorId = sensor.Id;
        sensor.SensorSamples.Add(sample);
    }
    // add the data to the sample
    sample.SampleData.Add(data);
}

我曾尝试通过分批(即一次 1000 条记录)来优化样本数据的插入。这确实有帮助,但即使SampleTime字段上有索引,随着更多记录的添加,查找查询似乎需要更长的时间。

所以,我的问题是,如何改进将样本数据添加到数据库的设计和/或性能?是否有更好的数据库结构来处理一对多关系?如果我可以在性能上获得适当的偏移,我愿意在数据库设计上做出一些妥协,但我仍然需要能够处理与给定的SampleTime.

4

3 回答 3

1

最大化测试数据的负载性能

    DONT run project in Debug mode (multiple factor slower for EF)

使用这些设置:

    Context.Configuration.LazyLoadingEnabled = false;
    Context.Configuration.ProxyCreationEnabled = false;
    Context.Configuration.AutoDetectChangesEnabled = false;
    Context.Configuration.ValidateOnSaveEnabled = false;

每 100 个或更少的条目,丢弃上下文。

 Using( new context)

尝试

Context.Set<TPoco>().AddOrUpdate(poco);

代替

   Context.Set<TPoco>().firstorDefault(lamba);
   Context.Set<TPoco>().Add(poco);
于 2013-08-29T04:47:44.547 回答
1

实体框架维护所有本地实体的本地缓存,并跟踪在这些实体中所做的任何更改。随着实体数量的增加,检查变得更加昂贵。

是一个非常有趣的系列文章,介绍 DetectChanges 的工作原理以及您能做些什么。尤其是第 3 部分。

当我需要批量加载大量数据时,我禁用 DetectChanges 并在保存后清除本地缓存,以便释放内存:

    public static void ClearDbSet<T>(this DbContext context) where T : class {
        var entries = context.ChangeTracker.Entries<T>().Where(e => e.State == EntityState.Unchanged);

        foreach (DbEntityEntry<T> entry in entries.ToList()) {
            entry.State = EntityState.Detached;
        }
    }

ToList调用是必要的,否则迭代器将抛出异常。

于 2013-08-28T20:53:16.093 回答
0

EF6 beta 1 有一个可能适合您的目的的 AddRange 函数:

使用 Entity Framework 6 beta 1 插入多行

请注意,我链接到的文章是指 @felipe 所指的在 EF5 中将 AutoDetectChangesEnabled 设置为 false 的技术

于 2013-08-29T08:22:35.983 回答