如何阻止EF生成无用的代码,这有关系吗?

时间:2015-08-20 18:33:23

标签: c# sql-server performance linq entity-framework

我正在运行像

这样的linq查询
dbEntity.Where(x => x.FundType== "E")
        .Where(x => x.ReportDate == new DateTime(2014,10,23))
        .GroupBy(x => x.ReportDate)
        .Select(groupedDate => new CategorySourceData
            {
                ReportDate = groupedDate.Key,
                TotalFlow = groupedDate.Sum(x => x.Flow)
            }
        .ToList();

我希望它能给我与此查询相同的结果以及类似的运行时

select ReportDate,
       sum(flow)
from vwDailyFundFlowDetail
where FundType = 'E'
group by ReportDate

Ef生成一个返回正确数据的查询。但是,我的hanwritten查询在我的测试集上需要大约13秒,并且ef生成的查询在同一测试集上需要24秒。

ef查询看起来像

exec sp_executesql N'SELECT 
    1 AS [C1], 
    [GroupBy1].[K1] AS [ReportDate], 
     CAST( [GroupBy1].[A1] AS real) AS [C2]
    FROM ( SELECT 
        [Extent1].[ReportDate] AS [K1], 
        SUM([Extent1].[Flow]) AS [A1]
        FROM (SELECT 
      [vwDailyFundFlowDetail].[HFundId] AS [HFundId], 
      [vwDailyFundFlowDetail].[ReportDate] AS [ReportDate], 
      [vwDailyFundFlowDetail].[Flow] AS [Flow], 
      [vwDailyFundFlowDetail].[ForexChange] AS [ForexChange], 
      [vwDailyFundFlowDetail].[AssetsEnd] AS [AssetsEnd], 
      [vwDailyFundFlowDetail].[ShareID] AS [ShareID], 
      [vwDailyFundFlowDetail].[ShareClass] AS [ShareClass], 
      [vwDailyFundFlowDetail].[ISIN] AS [ISIN], 
      [vwDailyFundFlowDetail].[CUSIP] AS [CUSIP], 
      [vwDailyFundFlowDetail].[Ticker] AS [Ticker], 
      [vwDailyFundFlowDetail].[AssetsStart] AS [AssetsStart], 
      [vwDailyFundFlowDetail].[PortfolioChange] AS [PortfolioChange], 
      [vwDailyFundFlowDetail].[FundName] AS [FundName], 
      [vwDailyFundFlowDetail].[SSID] AS [SSID], 
      [vwDailyFundFlowDetail].[Advisor] AS [Advisor], 
      [vwDailyFundFlowDetail].[GEOID] AS [GEOID], 
      [vwDailyFundFlowDetail].[FTCID] AS [FTCID], 
      [vwDailyFundFlowDetail].[BenchIndex] AS [BenchIndex], 
      [vwDailyFundFlowDetail].[FundType] AS [FundType], 
      [vwDailyFundFlowDetail].[ETF] AS [ETF], 
      [vwDailyFundFlowDetail].[Domicile] AS [Domicile], 
      [vwDailyFundFlowDetail].[GeographicFocus] AS [GeographicFocus], 
      [vwDailyFundFlowDetail].[Currency] AS [Currency], 
      [vwDailyFundFlowDetail].[FundDomicile] AS [FundDomicile], 
      [vwDailyFundFlowDetail].[Manager] AS [Manager], 
      [vwDailyFundFlowDetail].[FundCurrency] AS [FundCurrency], 
      [vwDailyFundFlowDetail].[Benchmark] AS [Benchmark], 
      [vwDailyFundFlowDetail].[FundFocus] AS [FundFocus], 
      [vwDailyFundFlowDetail].[NetChange] AS [NetChange], 
      [vwDailyFundFlowDetail].[FundId] AS [FundId], 
      [vwDailyFundFlowDetail].[InstOrRetail] AS [InstOrRetail], 
      [vwDailyFundFlowDetail].[Hedge_yn] AS [Hedge_yn], 
      [vwDailyFundFlowDetail].[SRI_yn] AS [SRI_yn], 
      [vwDailyFundFlowDetail].[SCID] AS [SCID], 
      [vwDailyFundFlowDetail].[DistributorId] AS [DistributorId], 
      [vwDailyFundFlowDetail].[Distributor] AS [Distributor], 
      [vwDailyFundFlowDetail].[Frontier] AS [Frontier], 
      [vwDailyFundFlowDetail].[FundCategory] AS [FundCategory], 
      [vwDailyFundFlowDetail].[Commodity] AS [Commodity], 
      [vwDailyFundFlowDetail].[CurrId] AS [CurrId], 
      [vwDailyFundFlowDetail].[Idx] AS [Idx], 
      [vwDailyFundFlowDetail].[Bear] AS [Bear], 
      [vwDailyFundFlowDetail].[Dividend] AS [Dividend], 
      [vwDailyFundFlowDetail].[AbsoluteReturn] AS [AbsoluteReturn], 
      [vwDailyFundFlowDetail].[Islamic_yn] AS [Islamic_yn], 
      [vwDailyFundFlowDetail].[Ins] AS [Ins], 
      [vwDailyFundFlowDetail].[Inf] AS [Inf], 
      [vwDailyFundFlowDetail].[Silver] AS [Silver], 
      [vwDailyFundFlowDetail].[Gold] AS [Gold], 
      [vwDailyFundFlowDetail].[AG] AS [AG], 
      [vwDailyFundFlowDetail].[Metal] AS [Metal], 
      [vwDailyFundFlowDetail].[Administrator] AS [Administrator], 
      [vwDailyFundFlowDetail].[Custodian] AS [Custodian], 
      [vwDailyFundFlowDetail].[Bear2x] AS [Bear2x], 
      [vwDailyFundFlowDetail].[Bear3x] AS [Bear3x], 
      [vwDailyFundFlowDetail].[Leverage1x] AS [Leverage1x], 
      [vwDailyFundFlowDetail].[Leverage2x] AS [Leverage2x], 
      [vwDailyFundFlowDetail].[MuniStateId] AS [MuniStateId], 
      [vwDailyFundFlowDetail].[Leverage3x] AS [Leverage3x], 
      [vwDailyFundFlowDetail].[Synthetic_ETF] AS [Synthetic_ETF], 
      [vwDailyFundFlowDetail].[Physical_ETF] AS [Physical_ETF], 
      [vwDailyFundFlowDetail].[IG] AS [IG], 
      [vwDailyFundFlowDetail].[EMC] AS [EMC], 
      [vwDailyFundFlowDetail].[EMS] AS [EMS], 
      [vwDailyFundFlowDetail].[EMM] AS [EMM], 
      [vwDailyFundFlowDetail].[MuniState] AS [MuniState], 
      [vwDailyFundFlowDetail].[FundQualityId] AS [FundQualityId], 
      [vwDailyFundFlowDetail].[FundDurationId] AS [FundDurationId], 
      [vwDailyFundFlowDetail].[QualityName] AS [QualityName], 
      [vwDailyFundFlowDetail].[DurationName] AS [DurationName], 
      [vwDailyFundFlowDetail].[ClosedEnd] AS [ClosedEnd], 
      [vwDailyFundFlowDetail].[MLP] AS [MLP], 
      [vwDailyFundFlowDetail].[ArrivalTime] AS [ArrivalTime], 
      [vwDailyFundFlowDetail].[ArrivalDayCode] AS [ArrivalDayCode], 
      [vwDailyFundFlowDetail].[DActivationDate] AS [DActivationDate], 
      [vwDailyFundFlowDetail].[WActivationDate] AS [WActivationDate], 
      [vwDailyFundFlowDetail].[MActivationDate] AS [MActivationDate], 
      [vwDailyFundFlowDetail].[ShareClassCurrency] AS [ShareClassCurrency]
      FROM [dbo].[vwDailyFundFlowDetail] AS [vwDailyFundFlowDetail]) AS [Extent1]
        WHERE ((@p__linq__0 IS NULL) OR ([Extent1].[FundType] = @p__linq__1) OR (([Extent1].[FundType] IS NULL) AND (@p__linq__1 IS NULL))) AND (0 = (CASE WHEN ( EXISTS (SELECT 
            1 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
            WHERE 1 = 0
        )) THEN cast(1 as bit) ELSE cast(0 as bit) END))
        GROUP BY [Extent1].[ReportDate]
    )  AS [GroupBy1]',N'@p__linq__0 nvarchar(4000),@p__linq__1 varchar(8000)',@p__linq__0=N'E',@p__linq__1='E'

where子句的一部分

AND (0 = (CASE WHEN ( EXISTS (SELECT 
            1 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
            WHERE 1 = 0
        )) THEN cast(1 as bit) ELSE cast(0 as bit) END))

似乎是主要问题。据我所知,case语句总是0,所以这总是正确的。这部分查询的存在是从enter image description here

更改执行计划的单个部分 看起来像 enter image description here

如果我从where子句中删除case语句,那么这个查询的执行计划和运行时间以及我手写的sql就我所知道的那样变得相同。如何阻止EF添加where子句的这一部分?我在linq代码中做了什么让EF将其添加到查询中?

2 个答案:

答案 0 :(得分:2)

您需要在Configuration.UseDatabaseNullSemantics = true;

上设置DBContext

这会阻止添加的is null支票

https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.dbcontextconfiguration.usedatabasenullsemantics(v=vs.113).aspx

答案 1 :(得分:0)

我有类似的问题。

我猜你首先使用Datebase和EDMX文件。因此,请检查您的映射不是DefiningQuery。 打开EDMX并找到如下字符串:

<EntitySet Name="vwDailyFundFlowDetail" EntityType="yourbase.Store.vwDailyFundFlowDetail" store:Type="Tables" store:Schema="dbo" store:Name="vwDailyFundFlowDetail">
<DefiningQuery>SELECT 
  [vwDailyFundFlowDetail].[HFundId] AS [HFundId], 
  [vwDailyFundFlowDetail].[ReportDate] AS [ReportDate], 
  [vwDailyFundFlowDetail].[Flow] AS [Flow], 
  [vwDailyFundFlowDetail].[ForexChange] AS [ForexChange], 
  [vwDailyFundFlowDetail].[AssetsEnd] AS [AssetsEnd], 
  [vwDailyFundFlowDetail].[ShareID] AS [ShareID], 
  //...others
  FROM [dbo].[vwDailyFundFlowDetail] AS [vwDailyFundFlowDetail]</DefiningQuery>
</EntitySet>

用这样的smth替换它:

<EntitySet Name="vwDailyFundFlowDetail" EntityType="yourbase.Store.vwDailyFundFlowDetail" store:Type="Tables" Schema="dbo" />

检查,如果FundType必须可以为空。如果不是 - 将其标记为explicitly不可为空: set property to not nullable

我认为,它会有所帮助,以后我们可以研究新生成的查询。