C#Entity Framework在查询中使用模型中的类比使用匿名类慢

时间:2013-12-04 15:50:46

标签: c# entity-framework

我正在使用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查询中,我使用“包含”导航属性中的“数据”。我认为这种方式不应该多次访问数据库。查询运行大约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中运行它们都在相同的时间内返回相同的数据。

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

3 个答案:

答案 0 :(得分:2)

好的经过一些研究我发现问题是在后台的第一种情况下,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;

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

在我看来,第一个查询基本上会撤回导航属性中使用的实体上的每个属性,即使您不需要它们,第二个查询也使用投影,因此它只会检索那些您在查询中明确要求的属性...在此示例中仅显示策略名称,并忽略可能属于策略的所有其他内容。

虽然这已经过度简化了......想象下面的场景......(MyTable有X列数)

First Query很像:

SELECT * FROM MyTable

投影使EF能够更具体......

SELECT column1, column2, column3 FROM MyTable

这就是为什么你遇到了更快的查询。