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