实体框架6自动编译的查询

本文关键字:编译 查询 框架 实体 | 更新日期: 2023-09-27 18:30:00

我有一个查询,它在第一次执行时花费了一些时间。所有后续执行都非常快(即使数据不同)。我相信第一个执行EF是自动编译查询(构建查询计划等等),第二个调用是使用编译后的版本。这很好,除了第一个用户。那可怜的树液坏了。在糟糕的一天,EF执行时间将为2分钟(实际与SQL Server对话的时间为71ms,已通过SQL Server Profiler进行验证)

我已经着手预编译了视图,这确实节省了一些初始缓存的时间。

基本上,查询看起来有点像这个

dataSource.Component
    .Include(t => t.Table1)
    ... 37 tables later ...
    .Include(t => t.Table38)
    .Where(n=>n.Id == id).First()

现在我不能再摆弄数据模型了。但就背景而言,基本上每个表都是一个"表单"

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

除了在创业时温暖EF,我希望我错过了一些基本的东西?编译查询的管道似乎是一个相当黑的盒子?有没有一种方法可以连接到查询准备过程中,看看发生了什么?(也许没有抓住来源那么激烈…:)

实体框架6自动编译的查询

在我看来,你有两个选择:

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

    datasource.Component.SqlQuery("...").ToList();
    
  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);
    

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

    using(var datasource = new MyContext())
    {
        var result = CompiledQuery.Invoke(datasource,2).ToList();
    }
    

第二种选择可能最适合你。由于.NET 4.5,您的所有查询都会自动缓存为Func,如上所述,这解释了它第二次平稳运行的原因。手动创建委托应该可以在第一次运行查询时解决问题。