这是基于我面临的面试问题。
很短的定义可以
它可用于操作查询返回的行。
除了使用游标(点在MSDN上列出)之外,我有一个问题,如果我们可以使用查询或存储过程执行所有操作(如果我没记错的话,就像我们可以使用 Transact-SQL对于ms-sql),我们应该使用游标有什么具体的点吗?
这是基于我面临的面试问题。
很短的定义可以
它可用于操作查询返回的行。
除了使用游标(点在MSDN上列出)之外,我有一个问题,如果我们可以使用查询或存储过程执行所有操作(如果我没记错的话,就像我们可以使用 Transact-SQL对于ms-sql),我们应该使用游标有什么具体的点吗?
与大型结果集相比,使用游标就像使用视频流而不是一口气下载视频,并在下载后观看。如果你下载,你必须有几个演出空间和耐心等到下载完成。现在,无论你的机器或网络有多快,每个人看电影的速度都是一样的。
通常,任何查询都会在一次活动中被发送到服务器、执行,然后通过网络将结果集发送给您。游标将让您逐行访问数据,并仅在您请求时才流式传输每一行(实际上可以查看它)。
然而,这给我们带来了一些警告:
一致性:使用游标,您(通常)不会对数据的一致快照进行操作,而是对一行进行操作。因此,您的并发/一致性/隔离保证从整个数据库 (ACID) 下降到仅一行。您通常可以告知您的 DBMS 您想要什么级别的并发,但如果您过于挑剔(锁定您所在的完整表),您将浪费服务器端的许多资源节省。
单独传输每一行可能非常低效,因为每个数据包都有协商开销,您可以通过每个数据包发送大的(可能是压缩的)数据块来避免这种开销。(没有数据库服务器或客户端库愚蠢到可以单独传输每一行,两端都有缓存和分块,但它仍然是相关的。)
光标更难做对。考虑一个带有大结果集的查询,促使您使用游标,该游标使用带有聚合函数的 GROUP BY 子句。(这样的查询在数据仓库中很常见)。GROUP BY 可以完全破坏您的服务器,因为它必须一次生成和存储整个结果集,甚至可能在其他表上持有锁。
经验法则:
“顺序性”意味着您的查询中繁重的 GROUP BY 子句中没有聚合函数。服务器可以懒惰地决定为您的游标计算 10 行以从缓存中消耗并同时执行其他操作。
高温高压
游标是一种允许您迭代集合中记录的工具。它具有order和current record的概念。
通常,SQL
使用多重集进行操作:作为一个整体,这些是可能以没有给定顺序的重复记录的集合。
说,这个查询:
SELECT *
FROM a
JOIN b
ON b.a = a.id
, 对多集a
和进行操作b
。
此查询中的任何内容都不会对记录的顺序、它们的存储方式、访问顺序等做出任何假设。
这允许抽象出实现细节并让系统尝试选择最佳算法来运行此查询。
但是,在您转换完所有数据后,最终您将需要以一种有序的方式,一个一个地访问记录。
您并不关心电话簿的条目在硬盘驱动器上的存储方式,但打印机确实要求它们按字母顺序输入;并且格式标签应单独应用于每条记录。
这正是光标发挥作用的地方。每次在客户端处理结果集时,都在使用游标。您不会从服务器获得兆字节的未排序数据:您只会获得一个小变量:一个结果集描述符,然后编写如下内容:
while (!rs.EOF) {
process(rs);
rs.moveNext();
}
那是为您实现所有这些的游标。
这当然涉及数据库-客户端交互。
至于数据库本身:在数据库内部,您很少需要游标,因为正如我上面所说的,几乎所有数据转换都可以使用集合操作更有效地实现。
但是,也有例外:
SQL Server
得非常差。例如,使用游标可以比使用基于集合的操作更有效地计算累积和您还可能会发现这篇文章值得一读:
使用游标可以以编程方式顺序读取一组数据,因此它的行为方式类似于传统的文件访问,而不是 SQL 的基于集合的行为特征。
有几种情况可能会用到:
需要模拟基于文件的记录访问行为的地方——例如,关系数据库被用作一段代码的数据存储机制,而这段代码之前编写为使用索引文件进行数据存储。
如果需要按顺序处理数据 - 一个简单的示例可能是计算特定客户的运行总余额。(许多关系数据库,例如 Oracle 和 SQLServer,现在都对 SQL 进行了分析扩展,这应该会大大减少对此的需求。)
不可避免地,维基百科有更多:http ://en.wikipedia.org/wiki/Database_cursor
有时,基于集合的逻辑会变得非常复杂和不透明。在这些情况下,如果性能不是问题,则可以使用服务器端游标将关系逻辑替换为更易于管理和熟悉(对于非关系型思考者而言)的过程逻辑,从而更容易维护。
使用游标,您一次访问一行。因此,当您想要处理很多行但在给定时间只有一个时,最好使用它。
我在课堂上被告知,使用游标的原因是您想要访问的行数超过了您的记忆力——因此您不能将所有行都放入一个集合中然后循环遍历它。