在尝试从 EF5 升级到 EF6 时,我遇到了按可空列搜索表的显着性能差距。这是一个示例:
public class Customer
{
public int Id { get; set; }
public int? ManagerId { get; set; }
//public virtual Manager Manager { get; set; }
}
public class MyContext : DbContext
{
public MyContext(string connstring): base(connstring){}
public DbSet<Customer> Customers { get; set; }
}
class Program
{
static void Main(string[] args)
{
var db = new MyContext("CONNSTRING");
var managerId = 1234;
var q = from b in db.Customers
where b.ManagerId == managerId
select b.Id;
var s = q.ToString();
}
}
当 EF6 生成 SQL 时,它会添加一些用于 null 处理的逻辑:
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Customers] AS [Extent1]
WHERE (([Extent1].[ManagerId] = @p__linq__0)
AND ( NOT ([Extent1].[ManagerId] IS NULL OR @p__linq__0 IS NULL)))
OR (([Extent1].[ManagerId] IS NULL) AND (@p__linq__0 IS NULL))
注意同样的 linq 在 EF5 下产生了更简单的 SQL:
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Customers] AS [Extent1]
WHERE [Extent1].[ManagerId] = @p__linq__0
我可以理解开发人员试图实现的观点:如果您提供 null 作为参数,则 managerId = null 的查询将不会选择任何行。我感谢您的关心,但 99.9% 的搜索逻辑是分开的:一个用例查找
where ManagerId == null
, 另一个搜索特定 id where ManagerId == managerId
问题在于性能影响很大:MS SQL 不使用 ManagerId 上的索引,并且发生了表扫描。我的项目有数百个类似的搜索,在升级到 EF6 后,数据库大小约为 100GB,整体性能减少了大约 10 个。
问题是有人知道在 EF6 中禁用此障碍并生成简单 sql 的某种配置或约定吗?
编辑:
我在我的项目中检查了十几个类似的选择,发现:
搜索。即使在这种情况下也有轻微的性能损失:它
两次使用索引:第一次查找我在中指定的值
参数,第二次寻找空值
from p in db.PtnActivations
where p.Carrier != "ALLTEL"
where p.Carrier != "ATT"
where p.Carrier != "VERIZON"
生成 SQL
WHERE ( NOT (('ALLTEL' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL))) AND ( NOT (('ATT' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL))) AND ( NOT (('VERIZON' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL)))
没有利用我在运营商上的索引。 EF5 版本有
( NOT (('ALLTEL' = [Extent1].[Carrier]))) AND ( NOT (('ATT' = [Extent1].[Carrier]))) AND ( NOT (('VERIZON' = [Extent1].[Carrier]) ))
那个利用了它。
注意条件
('ALLTEL' = [Extent1].[Carrier]) AND ([Extent1].[Carrier] IS NOT NULL)
.第二部分是 总是 false,但添加此部分会放弃索引。我的大约 170 万条记录(通常需要大约 30 分钟)的例行导入持续了 3 小时,进度约为 30%。
最佳答案
放
db.Configuration.UseDatabaseNullSemantics = true;
获得您在 EF5 中的行为。此 workitem描述了
true
之间的区别和 false
是并且应该帮助您决定您是否接受旧行为。
关于entity-framework - EF6 SQL 生成 <where 可空列等于>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19672799/