【问题标题】:Why is my EntityFramework insert so slow?为什么我的 EntityFramework 插入这么慢?
【发布时间】:2017-07-20 10:14:08
【问题描述】:

我发现我的应用程序中的一个瓶颈是对一个特定实体的插入操作(通过导航属性插入三个表)。类定义如下:

public class TrackerState
{
    public int Id { get; set; }
    [Index]
    public int TrackerId { get; set; }

    [Index]
    public DateTime DateRecorded { get; set; }
    public DateTime DatePublished { get; set; }
    public DateTime DateReceived { get; set; }
    public LocationStatus LocationStatus { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public double Altitude { get; set; }
    public double Accuracy { get; set; }
    public string Source { get; set; }
    public double Speed { get; set; }
    public double Heading { get; set; }
    public int PrimaryOdometer { get; set; }
    public int SecondaryOdometer { get; set; }
    public int OperationalSeconds { get; set; }
    public virtual IList<AnalogState> AnalogStates { get; set; }
    public virtual IList<DigitalState> DigitalStates { get; set; }
}

public class AnalogState
{
    public int TrackerStateId { get; set; }
    public virtual TrackerState TrackerState { get; set; }
    public int Index { get; set; }
    public int Value { get; set; }
}

public class DigitalState
{
    public int TrackerStateId { get; set; }
    public virtual TrackerState TrackerState { get; set; }
    public int Index { get; set; }
    public bool Value { get; set; }
}

AnalogState 和 DigitalState 类使用 TrackerStateId 及其索引作为复合主键。

这些表目前非常小:

  • TrackerStates:2719
  • 模拟状态:0
  • 数字状态:32604

当我通过 SQL 管理工作室手动插入表时,操作会在几分之一秒内运行。当我使用以下代码通过 Entity Framework 插入时,最多可能需要 15 秒,所花费的时间很大程度上取决于跟踪器状态中包含的数字值的数量 - 例如具有 0 个数字值的跟踪器状态需要 0.1 到 0.5 秒,具有 64 个数字值的跟踪器状态需要 10 到 15 秒。

public async Task<int> AddAsync(TrackerState trackerState)
{
    using (var context = ContextFactory.CreateContext())
    {
        context.TrackerStates.Add(trackerState);
        await context.SaveChangesAsync();
        return trackerState.Id;
    }
}

基于此,似乎 Entity Framework 在后台执行的操作非常缓慢,但我不知道为什么。考虑到交易的频率,0.5 秒对于交易来说是相当慢的。 15秒实在是太慢了。到目前为止我尝试过的事情都没有成功:

  • 禁用更改跟踪。我没想到这会做很多事情,因为无论如何我都在为每个事务使用单独的上下文。
  • 首先插入跟踪器状态,然后在单独的步骤中插入数字状态。无论如何,实体框架可能正在内部执行此操作。

更新 1

我正在使用 EntityFramework 6.1.3。我不知道如何查看正在执行的 SQL,但我更新了存储库的 store 方法以使用 SQL 而不是 EF:

context.Database.ExecuteSqlCommand("INSERT INTO DigitalStates ([TrackerStateId], [Index], [Value]) VALUES (@Id, @Index, @Value)",
                    new SqlParameter("Id", entity.Id),
                    new SqlParameter("Index", digital.Index),
                    new SqlParameter("Value", digital.Value));

仅这一部分就占了大部分时间。插入 7 个条目需要 3 秒。

【问题讨论】:

  • 是否涉及任何验证?像最大值等?
  • 如果您尝试打开 SQL Server Profiler 并查看 EF 正在运行的查询需要 15 秒怎么办?
  • 据我所知,输入列没有验证。您在上面的模型中看到的正是用于生成表的内容(除了复合键)。
  • 您是否将记录器添加到查询中并查看正在执行的 SQL。还有你运行的是什么版本的 core 或 6?
  • 我使用Express Profiler 来查看您的查询 - 简单易用。强烈推荐。

标签: c# entity-framework


【解决方案1】:

在一次交易中保存所有数字状态会产生巨大的影响:

if (trackerState.DigitalStates.Count > 0)
{
    var query = "INSERT INTO DigitalStates ([TrackerStateId], [Index], [Value]) VALUES "
        + string.Join(",", trackerState.DigitalStates.Select(state => String.Format("({0}, {1}, {2})", entity.Id, state.Index, state.Value ? 1 : 0)));
    context.Database.ExecuteSqlCommand(query);
}

由于某种原因,让 Entity Framework 自动添加集合似乎是为添加的每个数字状态向数据库发出请求,尽管我的印象是它应该是一个事务,由上下文的 @ 触发987654322@ 方法。相对于集合的大小,此修复已将其从线性时间更改为近似恒定的时间。现在我的下一个问题是,为什么

【讨论】:

    猜你喜欢
    • 2012-11-19
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2012-10-17
    • 2021-10-20
    相关资源
    最近更新 更多