class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch stp = new Stopwatch();


            
            using(var db = new DBCommonContext();){
stp.Start();
var usser_First = db.tbUsers.Where(p => p.UserID > 0);//.AsEnumerable(); var users_Now = usser_First.Where(p => p.ModifyDate > new DateTime(2012, 8, 2)); //断点 foreach (var user in users_Now) {//断点 Console.WriteLine(user.UserName + "\n"); } stp.Stop(); Console.WriteLine("IQueryable执行时间:" + stp.Elapsed.ToString()+"\n"); stp.Reset(); } Console.ReadKey(); } }

 

设置好断点,打开SQL Profiler。分别对两个跟踪,可以看到到第一个断点的时候都还没有去SQL拿数据:

 

Linq查询IEnumerable与IQueryable

 

都是延迟执行,从SQL Profiler可以看出都是到foreach才去拿数据。

①、IEnumerable下执行的语句,可以看到去SQL加载过来的是第一个条件下的所有数据,然后扩展方法筛选。本质Linq2object,数据量略大内存占用多,响应速度也略快。

 

Linq查询IEnumerable与IQueryable

 

②、IQueryable下的结果,是根据语法书整个合并成sql查询到结果。本质linq2sql,耗损小,但查询效率略慢

Linq查询IEnumerable与IQueryable

 

组合查询的时候,我们一般会采取IQueryable<T>,最后ToList()的时候才会去数据库拿数据

 1 ...........
 2         using (var db = new YourEntitys())
 3                 {//linq组合查询
 4                     var query = from a in db.YourTable
 5                         select a;
 6  
 7                     if (YourTableDto.SystemId>0)
 8                     {
 9                         query = query.Where(p=>p.Id==YourTableDto.Id);
10                     }
11                     if (!string.IsNullOrEmpty(YourTable.Name))
12                     {
13                         query = query.Where(p => p.Name.Contains(YourTableDto.CategoryName));
14                     }
15 ..........

 

 

直接总结:

IEnumerable<T> 会直接加载所有数据到内存,然后再筛选。是先从数据库取出数据放入内存,然后在本地调用SKip 和 Take 等扩展方法

在调用自己的Where、SKip 、Take 等扩展方法之前数据就已经加载在本地内存里了。如上按第一个条件直接SQL加载到内存后,再自身执行第二个条件的数据。所以它传输的数据量比较大,所以会有更多的无用功。本质Linq2Object,额外带宽耗损大但速度快占内存。内存的读取速度要高于数据库之间筛选的速度

IQueryable<T> 会先翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。

所以在使用ORM、linq等的时候注意这两个接口,考虑好内存

是通过语法树完全转换成一个T-sql语句,最后SQL拿到结果集。只加载需要的数据。本质Linq2SQL。耗损小速度略慢。

选择哪个的问题其实是远程从sql加载数据和本地加载筛选数据的取舍

 

相关文章: