11

我正在尝试减少基于 EF 的应用程序的启动时间,但我发现即使对于单实体上下文,我也无法将初始读取所需的时间减少到 7 秒以下。特别奇怪的是,这一次不是特定于上下文类型的。

谁能解释导致这些缓慢时间的原因和/或我如何让事情运行得更快?

这是完整的示例代码:

在我的数据库中,我有一个名为 se_stores 的表,其中包含一个主键列 AptId:

    // a sample entity class
public class Apartment
{
    public int AptId { get; set; }
}

    // two identical DbContexts        

public class MyDbContext1 : DbContext
{
    public MyDbContext1(string connectionString) : base(connectionString)
    {           
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyDbContext1>(null);

        var config = new EntityTypeConfiguration<Apartment>();
        config.HasKey(a => a.AptId).ToTable("se_stores");
        modelBuilder.Configurations.Add(config);

        base.OnModelCreating(modelBuilder);
    }
}

public class MyDbContext2 : DbContext
{
    public MyDbContext2(string connectionString)
        : base(connectionString)
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyDbContext2>(null);

        var config = new EntityTypeConfiguration<Apartment>();
        config.HasKey(a => a.AptId).ToTable("apartments");
        modelBuilder.Configurations.Add(config);

        base.OnModelCreating(modelBuilder);
    }
}

    // finally, I run this code using NUnit:

var start = DateTime.Now;
var apt1 = new MyDbContext1(connectionString).Set<Apartment>().FirstOrDefault();
var t1 = DateTime.Now - start;
start = DateTime.Now;
var apt2 = new MyDbContext2(connectionString).Set<Apartment>().FirstOrDefault();
var t2 = DateTime.Now - start;
Console.WriteLine(t1.TotalSeconds + ", " + t2.TotalSeconds);

它可靠地打印如下内容:7.5277527, 0.060006。当我将测试切换为首先使用 MyDbContext2 时,我得到了相同的结果(因此无论哪个 DbContext 先初始化都会发生这种情况)。我还尝试使用 EF 电动工具预生成视图。这将第一个上下文的时间减少到大约 6.8 秒,因此只是一个小小的胜利。

我知道 DateTime.Now 是一种糟糕的分析方法,但是在使用 dotTrace 时这些结果仍然存在。我也知道第一次运行一些代码会调用 JITing 成本,但是 7 秒似乎太高了,不能归因于此。

我在 VS 2010 中使用 EF 4.3.1 和 .NET 4。

在此先感谢您的帮助!

编辑:有人建议打开 SQL 连接可能会导致问题。

  1. 我首先尝试使用原始 SqlConnection 运行随机查询并使用相同的连接字符串创建命令。这需要 1 秒,并且不影响 DbContext 初始化的时间。
  2. 然后,我尝试使用连接字符串创建一个 SqlConnection 并将其传递给 DbContext 的接受连接的构造函数。我通过了 contextOwnsConnection=false。这对 DbContext 初始化时间也没有影响。
  3. 最后,我尝试使用相同的凭据和连接字符串选项通过管理工作室进行连接。这几乎是瞬间的。
  4. 在 dotTrace 配置文件中,它测量 SqlConnectionFactory.CreateConnection(connectionString) 耗时 0.7 秒,这与原始 SQL 时间一致。

编辑:我想知道延迟是每次连接还是一次。因此,我尝试让 MyDbContext1 和 MyDbContext2 连接到不同服务器上完全不同的数据库。无论首先连接到哪个数据库,这都没有区别:第一个 DbContext 的使用大约需要 7 秒,而第二个上下文的使用速度非常快。

4

2 回答 2

8

将您编写的代码放入自己的项目中后,我发现项目的平台目标对 EF 框架的启动时间有很大影响。

在针对 x64 平台时,我收到了与您类似的结果(第一个 DbContext 旋转 7 秒,第二个旋转 <1 秒)。以 x86 为目标时,第一个 DbContext 的启动时间减少了大约 4 秒,降至 3.34633 秒,而第二个 DbContext 所需的时间与 x64 情况相似。

我不确定为什么会发生这种情况,但它必须与实体框架如何在不同环境中初始化自身有关。我在这里发布了一个单独的问题。

于 2012-09-25T14:12:29.100 回答
1

根据一些评论,第二个运行如此之快的原因是连接管理器缓存了连接。这使我相信获得初始连接是问题所在。

要尝试的事情:

  1. 更改连接字符串以使用数据库服务器的 IP 地址而不是其名称。

  2. 使用完全相同的凭据和机制使用 SQL Management Studio 连接到数据库服务器。从需要 7 秒的机器上执行此操作。假设这需要一段时间,请调查以查看正在使用的协议并确保您想要的协议是列表中的第一个。

  3. 在你的机器上安装一个网络分析仪,观察它的作用。

于 2012-09-24T22:36:26.507 回答