最近我在TSQL中讨论使用游标的问题.
首先,我不是辩论中的啦啦队长。但是每当有人说时,总会有一些傻瓜(或50)用强制性的“游标是邪恶的”咒语来猛击。我知道Server是为基于集合的操作优化的,也许游标确实是邪恶的化身,但是如果我想把客观的想法放在后面的话.
我的想法是这样的:
- **EDIT**: @Martin shows a good case where Cursors out-perform set-based operations fairly dramatically. I suspect that this wouldn't be the kind of thing you'd do _too_ often (before you resorted to some kind of OLAP / Data Warehouse kind of solution), but nonetheless, seems like a case where you really couldn't live without a cursor.
- [reference to TPC benchmarks](http://sqlblog.com/blogs/linchi_shea/archive/2007/10/09/t-sql-cursors-the-case-of-the-published-tpc-e-tests.aspx) suggesting cursors _may_ be more competitive than folks generally believe.
- [reference to memory-usage optimizations](http://blogs.msdn.com/b/sqlprogrammability/archive/2006/04/27/585170.aspx) _for cursors_ since Sql-Server 2005- **EDIT**: Set-based operations literally _cannot_ `Execute` stored procedures, etc. (see edit for item 1 above).
- **EDIT**: Set-based operations are exponentially slower than row-by-row when it comes to aggregating over large data sets.大多数情况下,我想在我的旧代码中将游标转换为基于设置的操作,如果/就像我对各种应用程序进行任何重大升级一样,只要从中获得一些好处。(在很多时候,我倾向于懒惰而不是纯洁--也就是说,如果它没有破裂,就不要修复它。)
发布于 2011-07-29 18:44:12
直接回答您的问题:
我还没有遇到这样一种情况,即set操作无法对游标执行其他操作。但是,在某些情况下,使用游标将一个大型集问题分解成更易于管理的块,对于代码可维护性、日志记录、事务控制等等,都是一个更好的解决方案。但是我怀疑是否有任何严格的规则来告诉您哪种类型的需求会导致一种或另一种解决方案--单个的数据库和需求太不一样了。
尽管如此,我完全同意你的“如果它没有坏,不要修复它”的做法。通过重构过程代码来为工作正常的过程设置操作,几乎没有什么好处。然而,首先寻求基于集合的解决方案,并且只在必要时进入过程代码,这是一条很好的经验法则。直觉?如果你使用游标超过20%的时间,你做错了什么。
和我真正想说的话:
当我采访程序员时,我总是会向他们抛出几个比较复杂的SQL问题,并向他们解释如何解决这些问题。我知道,这些问题可以通过set操作来解决,我正在特别寻找能够不用过程方法(即游标)来解决这些问题的候选人。
这并不是因为我认为在任何一种方法中都有任何内在的好的或更好的表现--不同的情况会产生不同的结果。更确切地说,这是因为,在我的经验中,程序员要么得到了基于集合的操作的概念,要么他们没有。如果他们不这样做,他们将花费太多的时间为问题开发复杂的过程解决方案,这些解决方案可以更快、更简单地通过基于集合的操作解决。
相反,获得基于集合的操作的程序员几乎从不在实现过程解决方案时遇到问题,而实际上,这是绝对必要的。
发布于 2011-07-29 22:44:55
运行总计是典型的情况,随着行数的增加,游标可以执行基于集合的操作,因为尽管游标的固定成本较高,但是所需的工作量是线性增长的,而不是像基于集合的“三角连接”方法那样呈指数增长。
Itzik Ben Gan在这里做了一些比较。

Denali对OVER子句有更完整的支持,但是这应该使这种使用变得多余。
发布于 2011-07-29 19:10:44
由于我已经看到人们使用其他TSQL构造(通常至少涉及一个while循环)来重新实现游标(在所有不同的表单中),所以没有什么是游标不能用其他构造完成的。
这并不是说,由于在解决方案中不包含“游标”一词,重新实现并不像游标那样效率低下。有些人似乎完全讨厌这个词,而不是机械。
我成功地提出保留游标的一个地方是在两个不同的数据库之间进行数据传输/转换(我们在这里处理客户端)。虽然我们本可以以一种基于集合的方式(实际上,我们以前已经实现过)来实现这个传输,但是有一些有问题的数据可能会给一些客户带来问题。在基于集合的解决方案中,我们要么必须:
然而,通过使单个客户端的传输单元(使用游标选择每个客户端),我们可以使每个客户端在系统之间的传输完全工作或完全回滚(即将每个传输放在自己的事务中)。
但是,我想不出有什么情况下我想要在这种传输的“顶层”以下使用光标(例如选择下一个要传输的客户端)。
https://stackoverflow.com/questions/6877507
复制相似问题