这是我所面临的面试问题。
非常简短的定义可以是
可用于操作查询返回的行。
除了使用游标(有关点列在MSDN上这里), 我有一个疑问,如果我们可以使用查询或存储过程执行所有操作(如果我没错,就像我们可以使用Transact-SQL进行MS-SQL),那么我们应该使用游标的任何具体要点吗?
这是我所面临的面试问题。
非常简短的定义可以是
可用于操作查询返回的行。
除了使用游标(有关点列在MSDN上这里), 我有一个疑问,如果我们可以使用查询或存储过程执行所有操作(如果我没错,就像我们可以使用Transact-SQL进行MS-SQL),那么我们应该使用游标的任何具体要点吗?
将每行数据单独传输可能非常低效,因为每个数据包都有协商开销,您可以通过发送大块且可能压缩的数据来避免这种情况。 (没有DB服务器或客户端库会愚蠢到单独传输每一行,双方都有缓存和分块,但仍然相关)
游标更难正确处理。考虑一个具有大结果集的查询,激励您使用游标,该查询使用带有聚合函数的GROUP BY子句。 (此类查询在数据仓库中很常见)。 GROUP BY可能会完全破坏您的服务器,因为它必须一次生成并存储整个结果集,甚至可能在其他表上持有锁。
经验法则:
“顺序性质”意味着您的查询中没有在重型GROUP BY子句中的聚合函数。 服务器可以懒惰地决定从高速缓存中计算供您的光标消耗的10行,并在此期间执行其他操作。
希望对您有所帮助
游标(cursor)是一种工具,允许您迭代一组记录。它具有“顺序”和“当前记录”的概念。
一般来说,SQL
操作的是多集合(multiset):这些是无固定顺序可能重复的记录的集合,作为一个整体处理。
比如,以下查询:
SELECT *
FROM a
JOIN b
ON b.a = a.id
操作多重集合a
和b
。
这个查询并不对记录的顺序、存储方式或访问顺序等做出任何假设。
这允许抽象掉实现细节,让系统尝试选择最佳查询算法。
然而,在你转换所有数据之后,最终你需要以一种有序的方式逐一访问记录。
你并不关心电话簿条目在硬盘上的存储方式,但是打印机需要按字母顺序输入它们;并且格式化标记应该逐个应用于每个记录。
这正是游标发挥作用的地方。每次在客户端处理结果集时,你都会使用一个游标。你不会从服务器获取几兆字节未排序的数据:你只获取一个微小的变量:一个结果集描述符,并且像这样写:
while (!rs.EOF) {
process(rs);
rs.moveNext();
}
这就是实现所有这些的光标。
当然,这涉及到数据库客户端的交互。
至于数据库本身:在数据库内部,你很少需要使用游标,因为正如我上面所说,几乎所有的数据转换都可以使用集合操作更有效地实现。
但是,也有例外:
SQL Server
中执行非常糟糕。例如,使用游标比使用基于集合的操作更高效地计算累积总和。您可能还会发现这篇文章值得一读:
100M
行都在一个FETCH
中吗? - Quassnoi使用游标可以一次访问一行。因此,当您想要操作大量行,但每次只操作一行时,最好使用它。
在我的课程中,我被告知使用游标的原因是您想要访问超过您内存容量的多个行 - 因此您无法将所有行都收集到一个集合中然后循环遍历。