使用数据库游标有什么好处?

Vik*_*kas 41 sql database cursor

它基于我面临的面试问题.

非常简短的定义可以

它可用于操纵查询返回的行.

除了使用光标(分列在这里的MSDN),我在我的脑海的一个问题是,如果我们可以利用执行查询或存储过程中的所有操作(如果我没有错,就像我们可以使用Transact-SQL对于ms-sql),我们应该使用游标吗?

And*_*asT 47

与大结果集相比,使用游标就像使用视频流而不是一次性下载视频,并在下载时观看它.如果你下载,你必须有一些空间和耐心等待下载完成.现在,无论您的机器或网络速度有多快,每个人都以相同的速度观看电影.

通常,任何查询都会在一次活动中发送到服务器,执行,并通过网络将结果集发送给您.游标将允许您逐行访问数据,并仅在您请求时对每行进行流式处理(实际上可以查看它).

  • 光标可以节省您的时间 - 因为您无需等待处理和下载完整的记录集
  • 它将节省您在服务器和客户端上的内存,因为它们不必将大量内存专用于结果集
  • 负载均衡网络和服务器 - 在"突发"模式下工作通常更有效,但它可以完全阻止您的服务器和网络.多用户环境很少需要这种延迟.流媒体为其他操作留出了空间.
  • 允许对查询表(在某些条件下)上的操作直接影响游标.因此,当您将光标放在行上时,其他进程可以读取,更新甚至删除其他行.这有助于特别是非常繁忙的表,许多并发读写.

然而,这给我们带来了一些警告:

  • 一致性:使用游标,您(通常)不会在数据的一致快照上操作,而是在一行上操作.因此,您的并发/一致性/隔离保证从整个数据库(ACID)只丢失到一行.您通常可以告知您的DBMS您想要的并发级别,但如果您太过挑剔(锁定您所在的完整表),您将丢弃服务器端的许多资源节省.

  • 单独传输每一行可能效率非常低,因为每个数据包都有协商开销,您可以通过每个数据包发送大的,可能是压缩的数据块来避免这种情况.(没有DB服务器或客户端库是愚蠢到足以单独传输每一行,两端都有缓存和分块,但仍然是相关的.)

  • 游标更难做对.考虑使用大结果集的查询,激励您使用带有聚合函数的GROUP BY子句的游标.(此类查询在数据仓库中很常见).GROUP BY可以完全废弃您的服务器,因为它必须立即生成并存储整个结果集,甚至可能在其他表上持有锁.

经验法则:

  • 如果您处理小型,快速创建的结果集,请不要使用游标.
  • 游标在临时性,复杂性(引用性),具有大结果集和低一致性要求的顺序性查询方面表现优异.

"顺序性"表示查询中的GROUP BY子句中没有聚合函数.服务器可以懒惰地决定为光标计算10行以从缓存中消耗并同时执行其他操作.

HTH

  • 谢谢。听起来像Python中的生成器。 (2认同)

Qua*_*noi 27

游标是一种允许您迭代集合中记录的工具.它有订单当前记录的概念.

通常,SQL使用多集合进行操作:这些是一组可能重复的记录,没有给定的顺序,作为一个整体.

说,这个查询:

SELECT  *
FROM    a
JOIN    b
ON      b.a = a.id
Run Code Online (Sandbox Code Playgroud)

,在multisets ab.

此查询中的任何内容都不会对记录的顺序,存储方式,访问顺序等进行任何假设.

这允许抽象出实现细节,并让系统尝试选择最佳算法来运行此查询.

但是,在转换完所有数据后,最终需要以有序的方式逐个访问记录.

您不关心电话簿的条目是如何存储在硬盘驱动器上的,但打印机确实要求它们按字母顺序输入; 并且格式化标签应单独应用于每个记录.

这正是游标发挥作用的地方.每次在客户端处理结果集时,都使用游标.您没有从服务器获取兆字节的未排序数据:您只需获得一个小变量:结果集描述符,只需编写如下内容:

while (!rs.EOF) {
   process(rs);
   rs.moveNext();
}
Run Code Online (Sandbox Code Playgroud)

这是为您实现所有这一切的光标.

这当然涉及数据库 - 客户端交互.

至于数据库本身:数据库中,你很少需要游标,因为正如我上面所说的,几乎所有的数据转换都可以使用set操作更有效地实现.

但是,也有例外:

  • 分析操作SQL Server都很差实施.例如,累积和可以使用游标比使用基于集合的操作更有效地计算
  • 处理数据块.存在这样的情况:应该将基于集合的操作顺序地应用于集合的一部分,并且应该独立地提交每个块的结果.虽然仍然可以使用基于集合的操作来执行此操作,但是通常使用游标是更优选的方法.
  • 在本机不支持它的系统中的递归.

您也可能会发现这篇文章值得一读:


Hur*_*rda 1

使用游标,您可以一次访问一行。因此,当您想要操作大量行但在给定时间只处理一行时,最好使用它。

我在课堂上被告知,使用游标的原因是您想要访问的行数超出了您的内存容量,因此您不能将所有行放入集合中然后循环遍历它。