繁体   English   中英

C#实体框架在查询中使用模型中的类比使用匿名类慢

[英]C# Entity Framework using class from model in a query slower than using anonymous class

我正在使用Entity Framework 5访问我的数据库。 该模型非常复杂,具有许多导航属性。 我已经使用linq编写了以下查询:

var myQuery =
        from cp in context.ClosedPositions.Include("Position").Include("Position.Folder").Include("Position.Strategy").Include("Position.Symbol").Include("Position.StopTargetPlacer")
        where cp.Position.EntryDate >= fromDT &&
        cp.ExitDate <= toDT &&
        (cp.Position.Folder.FolderCode == myFolder || showAllFolders) &&
        (cp.Position.Strategy.Name == myStrategy || showAllStrategies) &&
        (cp.Position.Symbol.Name == mySymbol || showAllSymbols) &&
        (cp.Position.Symbol.Exchange == myExchange || showAllExchanges)
        orderby cp.Position.EntryDate
        select cp;

导航的多样性如下:

位置1-* ClosedPostion

位置*-1个文件夹

排名*-1策略

位置*-1个符号

然后在foreach查询中,我使用Included导航属性中的Data。 我认为这种方式不应多次击中数据库。 查询运行大约6秒钟。

然后,我将查询重写为:

var myQuery =
        from cp in context.ClosedPositions
        join p in context.Positions on cp.PositionID equals p.ID
        join f in context.Folders on p.FolderID equals f.ID
        join sy in context.Symbols on p.SymbolID equals sy.ID
        join st in context.Strategies on p.StrategyID equals st.ID
        join stp in context.StopTargetPlacers on p.StopTargetPlacerID equals stp.ID
        where p.EntryDate >= fromDT &&
        cp.ExitDate <= toDT &&
        (f.FolderCode == myFolder || showAllFolders) &&
        (st.Name == myStrategy || showAllStrategies) &&
        (sy.Name == mySymbol || showAllSymbols) &&
        (sy.Exchange == myExchange || showAllExchanges)
        orderby p.EntryDate
        select new
        {
              ClosedPositionID = cp.ID,
              PositionID = p.ID,
              p.EntryChartID,
              cp.ExitChartID,
              p.EntryDate,
              cp.ExitDate,
              Symbol = sy.Name,
              Strategy = st.Name,
              p.Size,
              cp.Profit,
              STPlacer = p.StopTargetPlacer.Name,
              InitialRisk = p.InitialRisk,
              StrategyDirection = st.Direction
         };

同样,我使用了相同的foreach循环来处理数据。 这次,总处理时间仅为1秒左右。

我已经检查了两个LINQ查询生成的SQL查询,它们在SSMS中运行它们,并且它们在相同的时间内返回了相同的数据。

我的问题是,为什么在使用匿名类和上下文模型中的类之间会有巨大的延迟?

好的,经过一些研究,我发现问题在于,在第一种情况下,EF建立了变更跟踪结构,在第二种情况下,因为我使用的是匿名类,所以不会发生这种情况。 解决方案是AsNoTracking函数:

var myQuery =
    from cp in context.ClosedPositions.Include("Position").AsNoTracking().Include("Position.Folder").Include("Position.Strategy").Include("Position.Symbol").Include("Position.StopTargetPlacer")
    where cp.Position.EntryDate >= fromDT &&
    cp.ExitDate <= toDT &&
    (cp.Position.Folder.FolderCode == myFolder || showAllFolders) &&
    (cp.Position.Strategy.Name == myStrategy || showAllStrategies) &&
    (cp.Position.Symbol.Name == mySymbol || showAllSymbols) &&
    (cp.Position.Symbol.Exchange == myExchange || showAllExchanges)
    orderby cp.Position.EntryDate
    select cp;

我们在谈论多少条记录? 您是否在上下文级别禁用了实体跟踪?

请记住,当EF实现启用跟踪的实体时,它必须检查来自数据库的每条记录,以确保它不会再次实现同一对象。 跟踪实体也更加昂贵,因为它必须注册所有实体(更多代码执行)。 当您实现匿名类型时,上下文不必担心所有这些。

在我看来,第一个查询将基本上撤回导航属性中使用的实体上的每个属性,即使您不想要它们,第二个查询也正在使用投影,因此它只会检索您拥有的那些属性在您的查询中专门要求的...在这种情况下,仅以“策略”名称为例,而忽略了可能属于该策略的其他所有内容。

尽管这过于简化了...想象以下情况...(MyTable的列数为X)

第一个查询很像:

SELECT * FROM MyTable

通过投影可以使EF更加具体...

SELECT column1, column2, column3 FROM MyTable

这就是为什么您遇到一个更快的查询的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM