我先走。
我是 100% 在集合操作阵营。但是,当整个所需输入域上的设置逻辑导致如此大的检索以致查询显着减慢、爬行或基本上需要无限时间时会发生什么?
在这种情况下,我将使用可能最多数十行的小光标(或 while 循环)(而不是我的目标数百万行)。因此,我仍在(分区子)集中工作,但我的检索运行得更快。
当然,更快的解决方案是从外部并行调用分区输入域,但这会引入外部系统的交互,并且当可以通过串行循环实现“足够好”的速度时,可能不值得它(特别是在开发过程中)。
我先走。
我是 100% 在集合操作阵营。但是,当整个所需输入域上的设置逻辑导致如此大的检索以致查询显着减慢、爬行或基本上需要无限时间时会发生什么?
在这种情况下,我将使用可能最多数十行的小光标(或 while 循环)(而不是我的目标数百万行)。因此,我仍在(分区子)集中工作,但我的检索运行得更快。
当然,更快的解决方案是从外部并行调用分区输入域,但这会引入外部系统的交互,并且当可以通过串行循环实现“足够好”的速度时,可能不值得它(特别是在开发过程中)。
在很多情况下,必须读取配置表中的行并生成和执行代码,或者在许多元编程场景中。
在某些情况下,游标只是因为优化器不够聪明而表现出色。在这些情况下,要么你头脑中的元信息根本没有通过表上的索引或统计信息显示给优化器,要么代码太复杂以至于连接(通常是重新连接)可以简单地不要以您可以以基于光标的方式可视化它们的方式进行优化。在 SQL Server 2005 中,我相信 CTE 倾向于使代码看起来更简单,但是很难知道优化器是否也认为它们更简单 - 归结为将执行计划与您认为可以完成的方式进行比较最有效地拨打电话。
一般规则 - 除非必要,否则不要使用游标。但在必要时,不要让自己为此感到难过。
有许多不同的光标行为。
除非您能解释所有这些选项以及默认情况下哪些选项是打开的,否则您永远不应该使用光标。
所以,我从不这样做。
相反,当我想在 T-SQL 中循环某些东西时……我将它加载到一个变量表中,这类似于 LOCAL STATIC SCROLL 游标……除了它可以被索引和连接(编辑:和防止使用并行性的缺点)。
在纯 SQL 环境中,我宁愿按照您的建议避免使用游标。但是,一旦您跨入过程语言(如 PL/SQL),就会有很多用途。例如,如果您想检索某些行并想要“做”一些比用它们更新它更复杂的事情。
偶尔你会得到一个需要游标的操作,但在 T-SQL 中这是相当罕见的。Identity(int) 列或序列以集合操作中的方式对事物进行排序。计算可能在某些点发生变化的聚合(例如从地面累积索赔到限制或超出点)本质上是程序性的,因此这些是游标的候选者。
其他候选者将本质上是程序性的,例如遍历配置表并生成和执行一系列查询。
当然,在许多地方游标可能比基于集合的操作更好。
一种是如果您要更新表中的大量数据(例如,按计划预先计算数据的 SQL 代理作业),那么您可能会使用游标在多个小集合中执行此操作,而不是在一个大集合中来减少并发锁定的数量,从而减少与访问数据的其他进程发生锁争用和/或死锁的机会。
另一种情况是,如果您想使用sp_getapplock
存储过程获取应用程序级别的锁,这在您想确保被多个进程轮询的行只检索一次时很有用(这里的示例)。
不过总的来说,我同意最好尽可能开始使用基于集合的操作,并且仅在出于功能或性能原因需要时才移动到游标(有证据支持后者)。
与David B所说的一样,我也更喜欢循环/表格方法。
除此之外,游标和循环/表方法的一个用例涉及非常大的更新。假设您必须更新 10 亿行。在许多情况下,这可能不需要是事务性的。例如,它可能是一个数据仓库聚合,如果事情不顺利,您有可能从源文件中重建。
在这种情况下,最好以“块”的形式进行更新,一次可能 100 万或 1000 万行。这有助于将资源使用保持在最低限度,并允许在更新数十亿行时最大化机器的并发使用。循环/分块方法在这里可能是最好的。不那么出色的硬件上的十亿行更新往往会导致问题。
当您想使用不同的输入值多次运行系统过程时,游标也很方便。我无意尝试将系统过程重写为基于集合的,因此我将使用游标。另外,您通常会经过非常有限数量的对象。您可以对一次仅插入一条记录的现有 proc 执行相同的操作,但从性能角度来看,如果您有很多记录要运行,这通常是一件坏事。那些我将重写为基于集合的。
其他人讨论的运行总计可以更快。
如果您是从数据库发送电子邮件(不是最好的主意,但有时这是您遇到的问题),那么当您发送相同的电子邮件时,光标可以确保客户 a 看不到客户 b 的电子邮件地址。
一个游标比集合更好的操作是在计算运行总数和类似的东西时。
必须使用游标通常表明您正在数据库中执行应在应用程序中执行的操作。正如其他人所说,当存储过程计算运行总计时,或者当您生成代码和/或元编程时,通常需要游标。
但是你为什么首先在存储过程中做这种工作呢?这真的是数据库服务器的最佳用途吗?T-SQL 真的是生成代码时使用的正确语言吗?
当然,有时答案是“是”,或者更有可能是“否,但这种方式更简单”。在我看来,让事情保持简单胜过一周中的任何一天的过早优化。所以我使用游标。但是当我认为我需要使用光标时,宇宙在问我一个我应该有一个很好的答案的问题。
如果一个表由于某种原因没有被索引,游标将比其他迭代表的方法更快。我去年在这篇关于 SQL Server 游标的 博客文章中找到了这些信息。
虽然作者赞成“仅作为最后手段使用”的方法(就像这里的每个人一样),但她确实发现了一两个案例,其中光标的性能以及其他可用的替代方案(包括 Robert Rossney 指出的运行总数) . 在她提出的其他有趣的观点中,她指出游标在存储过程中的操作比作为临时查询更有效。作者还出色地指出了我们都与游标相关的性能问题何时开始出现。
博客文章包含实际代码,因此读者可以自己尝试查询并查看结果。