简体   繁体   English

Linq to实体使用.Take()方法非常慢

[英]Linq to entities is very slow using .Take() method

I have a table of 200,000 record where I am getting only the top 10 using .Take() but it is taking about 10 seconds to get the data. 我有一个200,000记录的表,我只使用.Take()获得前10名,但是获取数据大约需要10秒钟。

My question is: does the .Take() method get all the data from the database and filter the top 10 on the client side? 我的问题是: .Take()方法是否从数据库获取所有数据并过滤客户端的前10位?

Here is my code: 这是我的代码:

mylist = (from mytable in db.spdata().OrderByDescending(f => f.Weight)
                                    group feed by mytable.id into g
                                    select g.FirstOrDefault()).Take(10).ToList();

spdata() is a function Import from stored procedure. spdata()是一个从存储过程导入的函数。

Thanks 谢谢

The stored procedure probably returns a lot of data to the client which is very slow. 存储过程可能会向客户端返回大量数据,这非常慢。 You cannot remote a query to an sproc. 您无法远程查询sproc。 That would be possible using a view or a table-valued function. 这可以使用视图或表值函数。

There's no way to use an sproc in a query. 在查询中无法使用sproc。 You can only execute it by itself. 您只能自己执行它。

Your intention probably was to execute the Take(10) on the server. 您的意图可能是在服务器上执行Take(10) For that to work you need to switch to an inline query, a view or a TVF. 为此,您需要切换到内联查询,视图或TVF。

The extension method Take does not fetch all the results from the database. 扩展方法Take 获取所有从数据库中的结果。 That is not how Take works. 这不是Take工作原理。

However your db.spdata() call probably does fetch all rows. 但是, db.spdata()调用可能会获取所有行。

I'm not 100% sure but as I remember you get an IEnumerable result when you call an SP using EF DataContext... 我不是100%肯定,但是当我记得你使用EF DataContext调用SP时会得到一个IEnumerable结果...

There are a couple of was to optimize the performance: 有几个是优化性能:

  • Pass the search criteria s as SP params and do the filtering in the stored procedure. 将搜索条件s作为SP参数传递,并在存储过程中进行过滤。

Or if you have a quite simple query in the SP where you are not declaring any variables and where you are just joining some tables then: 或者,如果您在SP中有一个非常简单的查询,您没有声明任何变量,而您只是加入某些表,那么:

  • Create an indexed view where specify the query that you need and call the Take method on it. 创建一个索引视图,在其中指定所需的查询并在其上调用Take方法。
    What this will give you? 这会给你什么? You can map to the created view and EF will now be returning an IQueryable result and not an IEnumerable. 您可以映射到创建的视图,EF现在将返回IQueryable结果而不是IEnumerable。 This will optimize the sql command and rather the receiving all of the data and then taking the 10 elements that you need, a sql command that just retrieves the 10 elements will be formed. 这将优化sql命令,而不是接收所有数据,然后获取所需的10个元素,将形成一个只检索10个元素的sql命令。

I also advice you to see what is the deference between IEnumerable vs IQueryable. 我还建议你看看IEnumerable和IQueryable之间的差异是什么。

It does, because you are sorting the data before grouping, which is not possible to do in SQL. 确实如此,因为您在分组之前对数据进行排序,这在SQL中是不可能的。

You should use an aggregate to get the highest weight from each group, then sort the weights to get the ten largest: 您应该使用聚合来从每个组中获得最高权重,然后对权重进行排序以获得最大权重:

mylist = (
  from mytable in db.spdata()
  group feed by mytable.id into g
  select g.Max(f => f.Weight)
).OrderByDescending(w => w).Take(10).ToList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM