实体框架6自动编译查询

J R*_*ose 5 c# entity-framework

我有一个查询,在第一次执行时花了一些时间.所有后续执行都非常快(即使使用不同的数据).我相信第一次执行EF是自动编译查询(构建查询计划,等等等等),第二次调用是使用编译版本.哪个好,除了第一个用户.那可怜的汁液被搞砸了.在糟糕的一天,EF执行将是2分钟(71ms实际上与SQL Server通信 - 使用SQL Server Profiler验证.)

我已经开始预先编译了这些视图,这些视图在初始缓存时节省了一些时间.

基本上查询看起来像这样

dataSource.Component
    .Include(t => t.Table1)
    ... 37 tables later ...
    .Include(t => t.Table38)
    .Where(n=>n.Id == id).First()
Run Code Online (Sandbox Code Playgroud)

现在我无法摆弄数据模型.但对于背景,基本上每个表都是一个'表单'.

SQL Server Profiler输出基本上是一个带表的大UNION,但执行速度非常快,所以我不认为问题是表格布局/键...

除了在启动时加热EF,我希望我遗漏一些基本的东西?看起来编译查询的管道非常黑盒子?有没有办法挂钩查询准备过程,看看有什么进展?(也许比抓住源头更不强烈...... :)

Ale*_*rck 2

我认为你有两个选择:

  1. 使用已知的 sqlQuery,并仅针对这一查询通过 DbContext 将其作为原始 sql 执行,如下所示

    datasource.Component.SqlQuery("...").ToList();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以使用返回的委托IQueryable来预编译您的表达式:

    public static Func<MyContext,int,IQueryable<Component>> CompiledQuery = (ctx,id) => 
           ctx.Include(c => c.Table1)
              .Include(c => c.Table2)
              ...
              .Include(c => c.Table38)
              .Where(n => n.Id == id);
    
    Run Code Online (Sandbox Code Playgroud)

    然后在您的代码中您可以使用Invoke查询:

    using(var datasource = new MyContext())
    {
        var result = CompiledQuery.Invoke(datasource,2).ToList();
    }
    
    Run Code Online (Sandbox Code Playgroud)

第二种选择可能最适合您。从 .NET 4.5 开始,您的所有查询都会自动缓存为 Func,如上所述,这解释了为什么它第二次运行顺利。手动创建委托应该可以在您第一次运行查询时解决您的问题。

  • 我认为,问题不在于未编译的查询。我敢打赌,90%的时间都是物体物化 (2认同)