B\S备忘录23——EF参数使用错误引起全表查询

  前几天是临危受命,跟着师哥一起解决数据查询太慢的问题。最近时间太少,没有静下心来好好总结一下,都过了一个多星期了,再不写点东西就快忘了。- -

  一开始的时候我们都认为数据查询太慢是WCF传输得问题,所以师哥带着我们从最简单的开始,把现在用的框架逐个击破。我们的框架使用EF进行对数据库的操作,首先就分成了两组,一组做使用EF查询的Demo,一组使用ADO.Net写了一个SQLhelper进行查询。

  这两组查询的结果,总共60万条数据,全部查询出来都是10秒多一点,从监控的时间来看是差不多的,EF会慢一点。之后进行了分页查询模拟,仅在60万条数据中查询前10条,检测到的数据在零点几秒,时间差很小可以忽略不计。

  到这里我们确定了,查询缓慢并不是使用了EF的问题,再然后我们在前两个Demo的基础上加入了WCF,再次测试之后,发现就算是经过WCF,查询的速度仅仅比不用WCF多了1秒。现在看来,并不是WCF的问题,那么问题到底在哪呢?

  我们在项目中使用的查询,是继承了底层封装好的查询功能,那么我们就直接使用了现在系统中的底层查询方法。结果很奇怪,在更换了基础的数据库之后,里面总共有4万条数据,查询所有数据的时间是6秒,而查询前10条的结果却是26秒,查询前十条数据怎么会比查询所有的还慢呢?而且还慢了20秒。

  那么现在我们的眼光就订到了底层的分页查询上了,询问了熟悉底层方法的人了解到了一个情况,底层从来没有实现分页查询,从来都是查询出来多有的数据,然后根据分页擦查询的参数进行筛选,选出应该看到的那十条数据,换句话说,假分页。

  如果我们不用底层呢?直接使用EF进行查询,查询条件都一直的情况下,查出10条的时间是2秒多。现在看来,是底层的问题。

  根据师哥的指导,我们分别对使用底层和不使用底层两种查询方式,进行了数据库的监测,看了一下EF发给SQL Server的语句。

  使用底层查询的SQL语句是这样的。

SELECT  
[Extent1].[Operator] AS [Operator], 
[Extent1].[TimeStamp] AS [TimeStamp], 
[Extent1].[IsEnabled] AS [IsEnabled], 
[Extent1].[OnClassStudentID] AS [OnClassStudentID], 
[Extent1].[OnClassID] AS [OnClassID], 
[Extent1].[StudentID] AS [StudentID]
FROM[dbo].[BasicOnClassStudentEntities] AS [Extent1]

 很明显能读出来这个是查询所有的数据。而是用EF进行查询的语句是这样的。

SELECT TOP (10) 
[Extent1].[Operator] AS [Operator], 
[Extent1].[TimeStamp] AS [TimeStamp], 
[Extent1].[IsEnabled] AS [IsEnabled], 
[Extent1].[OnClassStudentID] AS [OnClassStudentID], 
[Extent1].[OnClassID] AS [OnClassID], 
[Extent1].[StudentID] AS [StudentID]
FROM ( SELECT [Extent1].[Operator] AS [Operator], [Extent1].[TimeStamp] AS [TimeStamp], [Extent1].[IsEnabled] AS [IsEnabled], [Extent1].[OnClassStudentID] AS [OnClassStudentID], [Extent1].[OnClassID] AS [OnClassID], [Extent1].[StudentID] AS [StudentID], row_number() OVER (ORDER BY [Extent1].[StudentID] ASC) AS [row_number]
<span style="white-space:pre">	</span>FROM [dbo].[BasicOnClassStudentEntities] AS [Extent1]
)  AS [Extent1]
WHERE [Extent1].[row_number] > 159990
ORDER BY [Extent1].[StudentID] ASC

  现在看来就有点眉目了,查询的条件没有传给EF,但是为什么查询出来的结果依然是正确的呢?这个当时是没有解决的一个疑问,之后我会说明,继续我们的故事。

  这个时候,我又尝试了一次条件查询,发现查询的结果是一样的,数据库监控到的是查询所有,但是返回的结果就只用那么几条数据,两个方法相同的参数有一个,lambda表达式。

  当我们使用lambda表达式进行查询的时候,如果直接给EF,那么EF会根据这个表达式生成SQL语句。而是用底层的时候lambda表达式出了问题,没有被识别,就说明了传递参数的过程中出现了问题,参数传递的不对。

  之后我们进行了资料查询,最终得到了解决的方案,在传递lambda表达式的时候,参数类型使用的是Func<TSource,boll>,当我们把这个参数类型改为Expression<Func<TSource, bool>>,问题解决了,秒查。

  这两天我在做总结,发现了一片同样的博客,内容也是这个,里面解释了为什么会查询所有。

  将Func类型的变量作为参数传给Where方法进行LINQ查询时,Enitity Framework会产生全表查询,将整个数据库表中的数据加载到内存,然后在内存中根据Where中的条件进一步查询。(http://www.cnblogs.com/dudu/archive/2012/04/01/enitity_framework_func.html)

  我们遇到的所有问题都是有人遇到的,解决不了不是什么问题,但是我们一直忍受着缓慢的查询就是我们的问题了,还记得老师说过不将就是发现的原动力,这次3.0的项目中我们将就了那么长时间,最终也只是一个简单的小问题,哎,都把老师说得话都忘了啊。

  下次总计总结Expression<Func<TSource, bool>>和Func<TSource,boll>到底都是什么意思,看看为什么这两个会引起查询上的区别。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值