关于EF框架查询效率的疑惑

ying1234 2014-01-17 12:28:13
using (var edm = new testEntities())
{
System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo;

//foreach (test1 c in TwoCols)
//{

//}

// ViewBag.Message = TwoCols.Count();
}

表ClassInfo中有1千万条数据,
System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo;这个语句相当于
select * from ClassInfo,如果在数据库中直接用select * from ClassInfo需要好几分钟,为什么在页面中用System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo;反而页面直行得很快?
我看过TwoCols.Count()的确是1千万,为什么用System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo查1千万条数据会这么快,几乎1-2秒就出来了。
本要刚接触EF,还望有经验的各位解答。
...全文
567 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
ying1234 2014-01-18
  • 打赏
  • 举报
回复
为什么我这 IQueryable<ClassInfo> aa = TwoCols.AsNoTracking().OrderBy(p => p.ID).Take(1000);对应的SQl是 SELECT TOP (1000) [Extent1].[ID] AS [ID], [Extent1].[Name] AS [Name], [Extent1].[Addr] AS [Addr]FROM (SELECT [ClassInfo].[ID] AS [ID], [ClassInfo].[Name] AS [Name], [ClassInfo].[Addr] AS [Addr]FROM [dbo].[ClassInfo] AS [ClassInfo]) AS [Extent1]ORDER BY [Extent1].[ID] ASC 明明就是有嵌套查询的,我用的是 vs2013 Ado.net实体框架模型根据向导生成的,用的是实体框架5.0的版本,难道是版本不一样造成的?
romanchaos 2014-01-17
  • 打赏
  • 举报
回复
生成的是

SELECT TOP (1000) [T0].*
FROM [SKU] AS [t0]
ORDER BY [t0].[Id]
romanchaos 2014-01-17
  • 打赏
  • 举报
回复
引用 9 楼 ying1234 的回复:
不好意思,是我搞错了 第一种方式我少加了排序,所以执行要快得多, using (var edm = new testEntities()) { System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo; //IQueryable<ClassInfo> twoCol = from c in TwoCols // select c; IQueryable<ClassInfo> aa = TwoCols.AsNoTracking().OrderBy(p => p.ID).Take(1000); string strNames = string.Empty; foreach (ClassInfo c in aa) { strNames += "," + c.Name; } strNames.Substring(1); ViewBag.Message = strNames; } 如果加了排序,那么和esql的执行效率是差不多的。这二种方式产生的sql语句完全一样。 只是EF生成的SQL真是有够差的,象这样取前多少条的,按主键排序的sql非要生成一个嵌套查询的语句。 看来 EF 不太适合用在复杂查询上,否则生成的Sql挺可怕的。性能上要求高的也不适合。

SKU.OrderBy(p => p.Id).Take(1000)
生成的sql语句为

SELECT TOP (1000) [T0].*
FROM [EbayOnlineProduct] AS [t0]
ORDER BY [t0].[Id]
没有嵌套查询啊
ying1234 2014-01-17
  • 打赏
  • 举报
回复
引用 7 楼 wanghui0380 的回复:
不想说什么,优先实现,优先最小化 剩下滴具体实现具体优化 最简单比方,如果1加到100是最小功能点 那么 你 sum1to100这个方法里是 for循环,还是linq滴sum,还是等差数列求和公式,我并不想厉害 如果事实是sp1234说滴,在这个坛子里你得到滴linq sum是有问题滴,他就for呗,如果for还有问题那就等差数列求和公式呗 只要功能最小,只要你正交隔离,这点小问题,随时可以改进,根本不用放台面上讲
引用 8 楼 wanghui0380 的回复:
ps: System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo;这个语句相当于 select * from ClassInfo 呵呵,我不知道你从什么地方得到这个结论滴,你应该知道EF是延迟查询滴,你这个东西的到滴并不是select * from ClassInfo,而是IQueryable<ClassInfo>,具体滴sql执行,是根据你后面的方法得到滴(比如where,比如order,后面跟什么sql才解释成什么) 当然还是我上面说滴,优先实现,优先最小化,你管他xxoo滴性能做什么,俺们是第一线程序员,俺们不是博客园上那些喜欢矫情滴学院派,事实上说你这样没有明显问题,那么ok,如果事实上有问题,那么既然功能最小化,那怕你自己在这里用EF直接执行sql语句,有问题么??
开始时候真不知道是 延迟查询,刚刚开始入门 EF, 目前项目中还没有用到EF, 是我自已研究学习,既然是这样,那么效率问题也要关注一下。不然项目急着用,我也没这心思了,先实现再说。
ying1234 2014-01-17
  • 打赏
  • 举报
回复
不好意思,是我搞错了 第一种方式我少加了排序,所以执行要快得多, using (var edm = new testEntities()) { System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo; //IQueryable<ClassInfo> twoCol = from c in TwoCols // select c; IQueryable<ClassInfo> aa = TwoCols.AsNoTracking().OrderBy(p => p.ID).Take(1000); string strNames = string.Empty; foreach (ClassInfo c in aa) { strNames += "," + c.Name; } strNames.Substring(1); ViewBag.Message = strNames; } 如果加了排序,那么和esql的执行效率是差不多的。这二种方式产生的sql语句完全一样。 只是EF生成的SQL真是有够差的,象这样取前多少条的,按主键排序的sql非要生成一个嵌套查询的语句。 看来 EF 不太适合用在复杂查询上,否则生成的Sql挺可怕的。性能上要求高的也不适合。
wanghui0380 2014-01-17
  • 打赏
  • 举报
回复
ps: System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo;这个语句相当于 select * from ClassInfo 呵呵,我不知道你从什么地方得到这个结论滴,你应该知道EF是延迟查询滴,你这个东西的到滴并不是select * from ClassInfo,而是IQueryable<ClassInfo>,具体滴sql执行,是根据你后面的方法得到滴(比如where,比如order,后面跟什么sql才解释成什么) 当然还是我上面说滴,优先实现,优先最小化,你管他xxoo滴性能做什么,俺们是第一线程序员,俺们不是博客园上那些喜欢矫情滴学院派,事实上说你这样没有明显问题,那么ok,如果事实上有问题,那么既然功能最小化,那怕你自己在这里用EF直接执行sql语句,有问题么??
wanghui0380 2014-01-17
  • 打赏
  • 举报
回复
不想说什么,优先实现,优先最小化 剩下滴具体实现具体优化 最简单比方,如果1加到100是最小功能点 那么 你 sum1to100这个方法里是 for循环,还是linq滴sum,还是等差数列求和公式,我并不想厉害 如果事实是sp1234说滴,在这个坛子里你得到滴linq sum是有问题滴,他就for呗,如果for还有问题那就等差数列求和公式呗 只要功能最小,只要你正交隔离,这点小问题,随时可以改进,根本不用放台面上讲
ying1234 2014-01-17
  • 打赏
  • 举报
回复
明白了,感谢各位,我进一步做了测试 using (var edm = new testEntities()) { System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo; IQueryable<ClassInfo> aa = TwoCols.Take(1000); string strNames = string.Empty; foreach (ClassInfo c in aa) { strNames += "," + c.Name; } strNames.Substring(1); ViewBag.Message = strNames; } 取出了前1000条数据,累加了Name字段值,用以上这种方式,第一次运行得比较慢,大约7秒左右。第二次以的再刷新页面执行就非常快了。以道这个方式是有缓存在里面的,那表ClassInfo中数据有变动的时候办,有影响吗? 还有,我用esql的方式实现: using (testEntities edm = new testEntities()) { string esql = "select value c from testEntities.ClassInfo as c order by c.ID limit 1000"; ObjectQuery<ClassInfo> query = ((IObjectContextAdapter)edm).ObjectContext.CreateQuery<ClassInfo>(esql); ObjectResult<ClassInfo> results = query.Execute(MergeOption.NoTracking); string strNames = string.Empty; foreach (ClassInfo c in results) { strNames += "," + c.Name; } strNames.Substring(1); ViewBag.Message = strNames; } 用Esql的方式速度很慢,大约要20称左右,每次刷新都很慢,差不多都要求18--20秒。难道是没缓存引起的?如果速度差这么大,这个esql的方式还有什么用的意义?
mail_ylei 2014-01-17
  • 打赏
  • 举报
回复
System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo; //这行耗时0秒 TwoCols.Count();//执行命令 相当于select COUNT(*) from ClassInfo
romanchaos 2014-01-17
  • 打赏
  • 举报
回复
引用 3 楼 ying1234 的回复:
你所说的延迟加载的是个什么样的概念,执行了 System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo; 是不是一口气把表ClassInfo中的数据一口气都读到内存里了?
不是,这时候还未从数据库里拿数据,只有在foreach循环里有取/赋值(相当于reader)或者tolist(全部获取)的时候才会进行数据库操作,同理的还有firstordefault(相当于top 1)
ying1234 2014-01-17
  • 打赏
  • 举报
回复
你所说的延迟加载的是个什么样的概念,执行了 System.Data.Entity.DbSet<ClassInfo> TwoCols = edm.ClassInfo; 是不是一口气把表ClassInfo中的数据一口气都读到内存里了?
种草德鲁伊 2014-01-17
  • 打赏
  • 举报
回复
引用 1 楼 romanchaos 的回复:
延迟加载的问题,foreach里面如果有取值语句相当于reader就没那么快了,TwoCols.Count()相当于select COUNT(*) from ClassInfo那当然快。
+1
romanchaos 2014-01-17
  • 打赏
  • 举报
回复
延迟加载的问题,foreach里面如果有取值语句相当于reader就没那么快了,TwoCols.Count()相当于select COUNT(*) from ClassInfo那当然快。

8,497

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧