Linq to EF 中Contains的演变

在早期Linq to EF中没有提供对Contains方法的支持, 那时候只能将所有数据获取到内存中,然后通过Linq to Object的Contains方法来达到相同的效果(如果多表筛选也可以使用Any方法实现,也可采用自定义linq的方式实现,但这里我们主要讨论使用数组筛选表的情况)。

从Linq to EF 4.0 开始加入了对Contains的支持,使用方式如下:

以上linq最终会被翻译为如下形式的sql语句:

SELECT

[Extent1].[Name] AS [Name]

FROM [dbo].[TbA] AS [Extent1]

WHERE [Extent1].[Name] IN (@p1, @p1, @p1, @p1, @p1)

这句sql使用了参数@[email protected],因为Sql Server中参数不能超过2100个,这导致数组中元素超过2100个后,语句就无法执行。最后又只能回到使用linq to Object的Contains方法。

在EF 4.1后,EF会将数组中的值直接嵌入到sql语句中,以解决参数过多的问题。生成的sql如下:

SELECT

[Extent1].[Name] AS [Name]

FROM [dbo].[TbA] AS [Extent1]

WHERE [Extent1].[Name] IN (N‘a‘,N‘b‘,N‘c‘,N‘d‘,N‘e‘)

在EF 6.0之前, Contains方法生成的表达式树结构为多个DbExpression基础类使用OR的形式组合在一起的:

((1 = @p) OR (2 = @p)) OR ((3 = @p) OR (4 = @p))

当数组中的元素过多后,EF在生成上面的表达式树以及将表达式树转换为sql语句时,消耗了大增时间,可能导致EF在解析树时发生堆栈溢出的错误。在EF 6.0后,微软对EF中Contains方法的性能做出了优化,专门加入了DbInExpression类以提供对In语法的原生支持。以表就是优化前后的对比:


10000元素,执行10


优化前(ms


优化后(ms


1


163848


2589


2


155406


965


3


155255


959

测试代码如下(已清空TbA表中的数据):

最后说一下:在Sql Server中,当in中的元素比较少时,in 语句与使用or拼接查询条件的sql语句是等效的;当in中的元素比较多时,Sql Server会将元素保存到hash表后再做筛选。Sql语句中使用in后,SqlServer会使用全表扫描,但当元素为常量列表并且被筛选列有索引时,SqlServer会使用索引直接查找到结果集。

参考:

https://entityframework.codeplex.com/wikipage?title=Rebuilding%20EF%20providers%20for%20EF6

http://stackoverflow.com/questions/7897630/why-does-the-contains-operator-degrade-entity-frameworks-performance-so-drama/7936350#7936350

时间: 2024-10-11 07:54:42

Linq to EF 中Contains的演变的相关文章

linq to ef(相当于sql中in的用法)查询语句

select * from DoctorInfo doctor where doctor.HosDepartId in (select Id from HospitalDepartment hd where hd.DepartmentId=5) var a=from d in _entity.HospitalDepartment where d.DepartmentId==5 select d; List<int> lst=new List<int>();foreach(var b

EF架构~在Linq to Entity中使用日期函數

回到目录 眾所周知,在linq to entity的查询语句中,不允许出现ef不能识别的关键字,如Trim,Substring,TotalDays等.net里的关键字,在EF查询里都是不被支持的,它的原因可能是为了更好的提高查询的性能吧,毕竟,好的性能取决于你的程序标准,有了一个严格的标准,才能设计出好的程序来. 今天主要说一下,EF为日期方法留的一个后门,<后门>这个词大家在中国社会都应该知道了,顾名思义,就是反着原则走,你的原则对我没有用,哈哈!这东西有时候是有用的,因为在大的原则下,很可

应用开发之Linq和EF

上一章笔者对于WinForm开发过程用到的几个知识点做了讲解.笔者们可以以此为开端进行学习.而本章我们来讲一个跟ORM思想有关的知识点.在讲之前让我们想一下关于JAVA的hibernate知识点.hibernate也是ORM框架.记得hibernate里面有一个叫HQL.先不管HQL的好与坏.主要是明白HQL的目地是什么.ORM的思想就是为了让用户在操作数据的时候用上面向对象的思想来看,而不是二维数据了.所以HQL笔者认为就是一个面向对象思想的SQL语句.那么为什么笔者要讲到HQL呢?事实上笔者

EF中逆变和协变

EF中的增删改查: 实现步骤: 1.声明一个EF的上下文. bjhksjEntities dbContext = new bjhksjEntities(); 2.声明一个实体. HKSJ_USERS user = new HKSJ_USERS(); user.LoginName = "ssss"; user.Mail = "ssss"; user.PassWord = "ssss"; user.Plane = "ssss";

Java进击C#——应用开发之Linq和EF

本章简言 上一章笔者对于WinForm开发过程用到的几个知识点做了讲解.笔者们可以以此为开端进行学习.而本章我们来讲一个跟ORM思想有关的知识点.在讲之前让我们想一下关于JAVA的hibernate知识点.hibernate也是ORM框架.记得hibernate里面有一个叫HQL.先不管HQL的好与坏.主要是明白HQL的目地是什么.ORM的思想就是为了让用户在操作数据的时候用上面向对象的思想来看,而不是二维数据了.所以HQL笔者认为就是一个面向对象思想的SQL语句.那么为什么笔者要讲到HQL呢?

Linq to Entities中无法构造实体或复杂类型

EF中在使用linq就行查询select时不能直接使用自动映射生成的类,需要在单独声明一个类或者使用匿名类在查询完成后再转为对应的对象. 1 public partial class WebForm1 : System.Web.UI.Page 2 { 3 protected void Page_Load(object sender, EventArgs e) 4 { 5 using (aspnetdbEntities db = new aspnetdbEntities()) 6 { 7 //My

EF中的增删改查

在上一篇中简单的介绍了一下有关EF的一些概念,都是小编的一些个人理解,懂的不多,想深入学习的可以从网上查看一些其他资料. 下面紧接着上一篇所说,来从代码上看一下EF容器是如何实现与后台数据库之间的增删改查的. 1.EF包装类 什么是EF包装类呢?举个例子,我们平时用SQL语句写增删改查时,用的都是一些Insert.Update.Delete等语句来实现增删改查,所以我们把放到EF容器的东东也要做一个标签,来指明这个东东是要添加.更新.还是要删除呢. 正如上图所示就是这么简单的操作,就完成了对数据

EF中使用SQL语句或存储过程

EF中使用SQL语句或存储过程或视图 1.无参数查询var model = db.Database.SqlQuery<UserInfo>("select* from UserInfoes ").ToList(); 2.有参查询var model = db.Database.SqlQuery<UserInfo>("select* from UserInfoes where [email protected] ",new SqlParameter

EF 中获取 TableAttribute的值,即数据库中真实的表名

比如EF中我定义了这样一个实体: [csharp] view plain copy print? [Table(Name = "MyTableName")] public class MyClass { } [Table(Name = "MyTableName")] public class MyClass { } 现我想获取 MyTableName,可以这样来办: [csharp] view plain copy print? using System.Data.