linq是游标吗?

时间:2008-12-13 23:02:05

标签: .net linq linq-to-sql .net-3.5

我熟悉.NET和SQL。现在我正在看新的LINQ,它看起来就像一个光标。我理解易用性等,但如果我使用foreach循环执行LINQ-to-SQL查询,我只是使用数据库游标吗?或者在LINQ收集所有数据并一次一行地将其提供给我的程序的幕后有某种魔力吗?

3 个答案:

答案 0 :(得分:9)

不,它不是SQL意义上的游标。它不会一次迭代数据库中的行。相反,它使用您指定的条件动态构造查询。它会延迟查询的执行,直到需要第一个数据,然后对数据库执行查询。根据您使用数据的方式,可以为您缓冲数据,以便您可以逐行迭代它,或者如果您使用扩展方法获取列表,数组等,它可以将整个行集作为集合返回然而,就数据库而言,它只是执行一个SQL语句。

答案 1 :(得分:3)

LINQ有很多化身。既然你提到了LINQ-to-SQL,我就会关注它:它既不是......它与IDataReader最相似 - 即它执行一个构造的TSQL命令,然后返回处理过的记录row-by -row(见下文),因为它从SQL Server接收它们。与IDataReader一样,除非使用.ToArray().ToList()等缓冲数据,否则每行只有一次机会。

执行的TSQL命令是从您构建的LINQ查询构造的,并且参数化以防止SQL注入 - 因此,如果您使用“where”,则执行的TSQL包括“WHERE”等。

实际上,客户端通过IEnumerable[<T>]按需消耗记录,因此需要一个小缓冲区来处理传入的TDS流 - 但它与数据库游标不同。

请注意,大多数操作(排序等)可以发送到服务器并转换为TSQL - 但有可能必须在客户端完成某些操作,这可能会再次强制它在内存中缓冲更多数据。如果通过.ToEnumerable()强制执行此操作,则会切换到LINQ-to-Objects。如果LINQ-to-Objects执行缓冲操作(排序,分组等),则需要将数据加载到内存中。

这里有一些注意事项;例如,如果要在查询上计算完全独立的聚合等,则必须(通常)执行两次(等),或者将其全部缓存在内存中(不一定是大数据的选项)。对于这种类型的场景(和其他场景),Jon Skeet和我自己编写了一个替代LINQ实现,它可以作为 push 而不是 pull ,允许您通过多个提供数据并行进程一次完成。 Jon更好地解释了here。如果您想要进行复杂处理的非常大的一次性数据流,则主要使用此类事物。但有趣的是。

答案 2 :(得分:1)

只要您通过线路将数据库中的行返回到客户端,数据库服务器就会使用游标返回查询结果。

它是一个隐式游标,由数据库服务器控制,但它仍然是一个游标。

人们推荐使用显式游标的原因,以及它们比批量查询慢的原因是因为使用隐式游标,数据库服务器确切地知道它是如何被使用的。它可以优化对磁盘的访问,并且可以使用它用来控制对数据库的并发访问的锁定。使用显式游标,数据库服务器必须假设更糟糕的情况,因为它不知道何时或如何释放游标持有的锁。此外,数据库可以使用索引来提高批量查询的性能,如果您使用游标,则不会获得这些性能。但是,即使在简单的“返回整个表”的情况下,使用批量查询而不是游标也可以获得更好的性能。

当您运行DLINQ查询时,LINQ代码将转换为批量SQL查询,使用ADO.NET以与您生成查询字符串并提交它们时所写的方式类似的方式提交到数据库到数据库。

这会导致创建游标,但如果您直接提交批量查询并处理IDataReader,则会获得相同的隐式游标。