实体框架 - 荒谬的查询,将smallint转换为int进行比较

10 entity-framework entity-framework-6

出于想法在这里.我有一个简单的表,模型首先与Entity Framework映射,我得到以下SQL生成:

(@p__linq__0 int,@p__linq__1 int)SELECT 
    [Extent1].[BucketRef] AS [BucketRef], 
    [Extent1].[VariantNo] AS [VariantNo], 
    [Extent1].[SliceNo] AS [SliceNo], 
    [Extent1].[TradeNo] AS [TradeNo], 
    [Extent1].[TradeBegin] AS [TradeBegin], 
    [Extent1].[TradeEnd] AS [TradeEnd], 
    FROM [simstg].[Trade] AS [Extent1]
    WHERE ((( CAST( [Extent1].[BucketRef] AS int) = @p__linq__0) AND ( NOT (( CAST( [Extent1].[BucketRef] AS int) IS NULL) OR (@p__linq__0 IS NULL)))) OR (( CAST( [Extent1].[BucketRef] AS int) IS NULL) AND (@p__linq__0 IS NULL))) AND ((( CAST( [Extent1].[VariantNo] AS int) = @p__linq__1) AND ( NOT (( CAST( [Extent1].[VariantNo] AS int) IS NULL) OR (@p__linq__1 IS NULL)))) OR (( CAST( [Extent1].[VariantNo] AS int) IS NULL) AND (@p__linq__1 IS NULL)))
Run Code Online (Sandbox Code Playgroud)

所有这些演员都会杀死他们.我很遗憾没看到他们来自哪里.

有问题的查询是:

var tradesQuery = repository.SimStgTrade
    .Where(x => x.BucketRef == bucketId && x.VariantNo == set)
    .ToArray();
Run Code Online (Sandbox Code Playgroud)

这很简单.字段定义为:bucketId:short(数据库中为smallint),设置为short,smallint为数据库.因此,完全不需要演员表.我已经删除并重新创建了模型中的表 - 据我所知,映射匹配(字段为smallint).因此,我们遇到了严重的性能问题 - 例如:查询超时,因为它不使用表扫描.

任何人都知道如何摆脱那些演员并迫使比较基于短裤?从SQL中可以看出,EF决定先将所有内容移动到一个int ......这没有任何意义.

这不是"很好"的事情.优秀的查询路径完全不同,结果代码将其转换为自联接.在服务器管理器中,EF变体需要超过5分钟,而带有简单SQL的优化版本需要0.0秒(在该表中返回数十亿的228行).

Ily*_*lya 16

由于C#编译器如何为Where表达式生成表达式树,因此这种行为对于不同的LINQ提供程序而言通常是常见的,而不仅仅是EF特定的.

将条件指定为:

.Where(x => x.BucketRef == bucketId)
Run Code Online (Sandbox Code Playgroud)

并且BucketRef和bucketId都是short,编译器为两个比较部分生成从short到int的强制转换,因为== operator不是为Short类型定义的.这将在答案/sf/answers/1300910061/中解释

作为一种解决方法,您可以通过以下方式重写条件:

.Where(x => x.BucketRef.Equals(bucketId))
Run Code Online (Sandbox Code Playgroud)

这有效地从比较中删除了演员.