下面的 C# 语句会阻塞进程并且无法检索数据,如果 itemToSkip 大于 0。
int itemToSkip = 100;
int itemToTake = 1000;
var itemList = db.MYTABLEs.Skip(itemToSkip).Take(itemToTake).ToList();
我该如何解决?有什么问题吗?
最佳答案
不确定您有哪个供应商提供 db.MYTABLEs。除非我们知道 db.MYTABLEs 的行为方式,否则真的不可能回答您的问题。
在正常的 LINQ 中,skip 不只是向前跳过;它必须遍历数据量才能跳过。因此,对于您的 14gb 数据表,它将遍历第一个“跳过”的记录数。如果此迭代很慢,则您不会通过跳过来节省任何 CPU/时间。
对于某些提供商,例如对于 SQL 源,skip 可以使用游标来实现,这又会很慢。如果是SQL Server,可能会用关键字优化,可能会更快。
如果它是 LINQ-to-SQL,它会使用“NOT EXISTS”子句将查询转换为 SQL,这将非常慢,因为它必须经过整个 table 如果 NOT EXISTS 子句没有命中索引。请参阅以下内容 ( link ):
LINQ to SQL translates Skip by using a subquery with the SQL NOT EXISTS clause. This translation has the following limitations:
The argument must be a set. Multisets are not supported, even if ordered.
The generated query can be much more complex than the query generated for the base query on which Skip is applied. This complexity can cause decrease in performance or even a time-out.
换句话说,文档说“不要这样做”。
仅适用于具有随机访问功能的提供商,例如一个内存数组,将非常快地跳过,因为提供者可以直接跳到前面。
最坏的情况是,如果您在使用 Skip/Take 时自动对整个数据集进行排序的提供程序上运行。如果您有 14gb 的数据,那么这种排序会非常慢。
您需要进行更多试验,看看您的程序是否在跳过时挂起,或者只是占用所有 CPU 以尝试迭代。
如果您只是想将数据分成可管理的 block ,您可能不应该使用 skip/take,它每次都会重新查询数据源。
关于c# - LINQ Skip() 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5261717/