2010-10-05 72 views
31

它是基于我面对的面试问题。使用数据库游标有什么好处?

非常短的定义可以是

它可以用来操纵查询返回的行 。

除了使用光标(点在MSDN上市here),我在我的脑海的一个问题是,如果我们可以利用执行查询或存储过程中的所有操作(如果我没有错,像我们可以为ms-sql使用Transact-SQL),有什么具体的观点我们应该使用游标?

+0

Quassnoi的链接包含一个不错的摘要段落: “游标可以作为foreach替代品,并将一些过程能力添加到基于集合的语言(SQL)中。对SQL没有经验的程序员倾向于滥用这个特性,他们不习惯于基于集合的SQL范例,并且试图做他们被教导要做的事情:打开一个循环,循环遍历它,用变量做一些事情,关闭“ – JsonStatham 2013-07-29 10:14:52

回答

1

随着光标你一次访问一行。所以,当你想用很多行进行操作,但在给定时间只有一行时,使用它是很好的。

我在我的班告诉记者,使用光标的原因是要访问除你能适应你的记忆更多的行 - 因此通过它你不能只是得到所有行到一个集合,然后循环。

+0

”我被告知在我的课堂上,使用光标的原因是你想访问更多的行,而不是你可以适应你的记忆“ - 告诉你的人 – 2010-10-05 11:51:53

+1

为什么结果集不需要在内存中,或者我错了? – Hurda 2010-10-05 15:57:42

+0

取决于您是指服务器(即数据库)还是客户端(即应用程序)内存。如果它是前者,那么该语句是无意义的,因为服务器必须保存游标的内容,如果它是后者,则该语句具有某种意义,尽管这样的结果分页更可能出于诸如网络带宽或用户方便比因为客户端内存限制,这些天。 – 2010-10-07 14:57:08

3

使用光标,可以通过一组数据,编程的顺序读出,所以它以类似的方式与常规的文件访问,而不是SQL的基于集合的行为特征的行为。

有一对夫妇的情况下,这可能是有用的:

  1. 在有必要模拟基于文件的记录访问行为 - 例如,在关系数据库被用作数据存储机制,用于以前编写为使用索引文件进行数据存储的一段代码。

  2. 如果有必要的过程数据顺序 - 一个简单的例子可能是计算为特定客户运行的总余额。 (A号码关系数据库,例如Oracle和SQLServer的,现在有分析扩展到SQL应大大减少这种情况的需要。)

不可避免的是,维基百科有更多:http://en.wikipedia.org/wiki/Database_cursor

25

游标是一个工具,允许您迭代集合中的记录。它有为了当前记录的概念。

通常,SQL与多重集运行:这些是一组中没有给定的顺序可能重复的记录,作为一个整体。

说,这个查询:

SELECT * 
FROM a 
JOIN b 
ON  b.a = a.id 

,对多集ab工作。

在此查询没有使有关的记录,他们是如何存储的顺序做任何假设,以何种顺序它们应访问等

这使得抽象出实施细则,并让系统尝试选择运行此查询的最佳算法。

但是,在完成所有数据转换之后,最终需要以有序方式逐一访问记录。

您不关心电话簿的条目是如何存储在硬盘上的,但打印机确实需要按照字母顺序输入;并且格式标签应该分别应用于每条记录。

这正是游标发挥作用的地方。每次在客户端处理结果集时,都使用游标。你不从服务器获取未排序的数据的兆字节:你只会得到一个微小的变量:一个结果描述符,只是写的是这样的:

实现这一切都为您
while (!rs.EOF) { 
    process(rs); 
    rs.moveNext(); 
} 

这就是光标。

这当然涉及数据库与客户端的交互。对于数据库本身:里面的数据库,你很少需要游标,因为,正如我上面告诉过的那样,几乎所有的数据转换都可以使用set操作更高效地实现。

不过,也有例外:

  • 分析操作SQL Server实现很差。例如,使用光标可以比使用基于集合的操作更高效地计算累积总和
  • 以块处理数据。在某些情况下,应该将集合操作顺序应用于集合的部分,并且应该独立提交每个块的结果。虽然仍然可以使用基于集合的操作来完成,但光标往往是更好的方法。
  • 递归在本机不支持它的系统中。

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

+0

您的意思是客户端每次需要新记录时都会将FETCH命令发送到服务器?它一定是非常无效的。为什么不把所有结果一次加载到客户端? – 2012-06-08 06:59:51

+0

@IvanVirabyan:你将如何处理这些数据? – Quassnoi 2012-06-08 07:03:53

+0

在大多数情况下,我会以某种方式显示它 – 2012-06-08 07:17:02

38

使用游标比较大的结果集是喜欢用视频流,而不是下载一举的视频,看它已经下载了。 如果你下载,你必须有一些空间和耐心等待,直到下载完成。现在,无论您的机器或网络多快,每个人都会以相同的速度观看电影。

通常,任何查询都会发送到服务器,执行并且结果集通过网络发送给您。 只有当您请求它(实际上可以查看它)时,光标才会允许您按行访问数据行并对每行进行流式处理。

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

但是这给我们带来了一些注意事项,:

  • 一致性:使用光标,你这样做(通常)未对数据的一致性快照操作,但在一排。因此,您的并发/一致性/隔离保证从整个数据库(ACID)只丢弃到一行。您通常可以通知您的DBMS需要什么级别的并发性,但是如果您太过挑剔(锁定您所在的整个表),则会在服务器端丢弃许多资源节省。

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

  • 游标难以正确执行。考虑一个带有大结果集的查询,激励你使用一个使用聚合函数的GROUP BY子句的游标。 (这种查询在数据仓库中很常见)。 GROUP BY可以完全垃圾你的服务器,因为它必须一次生成并存储整个结果集,甚至可以在其他表上保留锁。

经验法则:

  • 如果小,快速创建结果集工作,不使用游标。
  • 游标擅长特设,复杂(参考),连续性查询,结果集大且一致性要求低。

“顺序性”意味着在查询中重度GROUP BY子句中没有聚合函数。服务器可能会懒惰地决定计算10行,以便从缓存中消耗光标并同时执行其他操作。

HTH

+0

“它可以节省你的内存,无论是在服务器上还是在客户端上,因为他们不必为结果集专门分配大量内存”。如果数据不符合我的记忆,我该怎么办?如果我必须以某种方式对它进行聚合,为什么我不使用sql?如果我想显示所有的结果,我仍然需要它来适应内存。如果我想显示它的一个子集 - 我可以使用sql来获取子集。你能提供一个例子,当我真的需要使用游标吗? – 2012-06-08 07:09:31

0

有时基于集合的逻辑可以得到相当复杂和不透明。在这些情况下,如果性能不是问题,则可以使用服务器端游标来用更易于管理和熟悉的(对于非关系思考者)程序逻辑来替代关系逻辑,从而更易于维护。

相关问题