What Every DBA Ought to Know About SQL Server Cursors (and Their Alternatives)

本文详细介绍了SQL Server中游标的四种类型及其行为特性,并探讨了游标的性能调优方法及替代方案。

原文地址:http://www.databasejournal.com/features/mssql/article.php/3896206/What-Every-DBA-Ought-to-Know-About-SQL-Server-Cursors-and-Their-Alternatives.htm

What is a Cursor

A cursor is used to process through a result set one row at a time. Often times this is used for batch processing. There are four types of cursors: static, dynamic, keyset, and forward-only.

Static cursors have their data and result set fixed at the time the SELECT associated with the cursor is executed (when the cursor is opened). It will not see any modifications made by other users including inserts that may match the query criteria or deletes that would have removed rows. Tempdb is enlisted to hold this snapshot of the result set. Therefore, the result set must conform to the limits of a single table. Static cursors are not updateable.

Dynamic cursors detect all changes to the underlying result set as it scrolls. Scrolling can occur in any direction and the cursor may change its result set and/or order with every fetch (pointing to another row). This means a dynamic cursor consumes more resources performing its work than does the static cursor.

Keyset cursors, as their name implies, are sets of keys that identify the rows in the result set. As the cursor is scrolled through, the data is retrieved for those key values. Unlike dynamic cursors, the membership and order of the rows in the result set are fixed once the cursor is opened. Due to the nature of keyset cursors, it is still possible for other user's changes to data associated with the cursor and its members to be reflected in the fetch of any given row.

The final cursor type of forward-only isn't really a separate type for SQL Server as it can be specified in addition to any one of the other types. This is more of a behavior than a type as it specifies that the cursor can only scroll forward to the next row in the result set and never backward.

The behavior of a cursor is affected by two keywords: SCROLL and INSENSITIVE. SCROLL tells SQL Server you reserve the right to scroll both forward and back through the result set instead of just forward. You can specify whether the cursor will ignore changes to the underlying data as it scrolls by declaring the INSENSITIVE option. This also makes the cursor read-only. Additionally, you can specifically declare that the cursor is not updateable by using the READ ONLY option.

It is important to note that combinations of behaviors and cursor types are not recommended by Microsoft and may produce unexpected behavior. That being said, forward-only cursors default to a dynamic type. Dynamic, static, and keyset cursors default to the SCROLL behavior.

Cursor Tuning

Depending on the purpose behind the cursor, there are multiple options available for performance tuning. The goals of performance tuning are not only to increase the performance of the cursor itself, but also of other SQL Server operations that may be contending for the same data or resources.

First and foremost, make sure to tune the SELECT statement from which the cursor is built. Ensure that it only returns the number of rows necessary for the processing being performed. If need be, provide additional criteria in the WHERE clause. Also, reduce the number of columns returned by the result set to just those necessary for processing. This reduces the resources required by the cursor to keep track of the data.

If the cursor is used for reference only and not for updates, make sure the cursor specifies the READ ONLY option if it is not already read only (such as a static or insensitive cursor). This makes sure the cursor doesn't hold locks on the underlying tables thus reducing concurrency. If you only need to move forward through the cursor, FAST_FORWARD will get you the read only access you need while reducing overhead. This is similar to FORWARD_ONLY; however, FORWARD_ONLY can be used with cursors that need to update the underlying data.

If you are suffering from contention on your updates, try changing your cursor to OPTIMISTIC. This specifies that changes made to the row updated through the cursor will be timestamp checked and fail if the row was changed after it was fetched. If, however, you need all the cursor related changes to succeed, you can use SCROLL_LOCK to lock the result set rows when the results are retrieved. This method increases contention with other users of the underlying data and should be used only after much consideration.

Hopefully you don't come across this in your tuning duties, but another thing to look out for is whether the cursor is being properly closed and deallocated. Closing and deallocating the cursor allows SQL Server to free up any locks associated with the underlying tables as well as free up resources allocated to the cursor.

Alternatives to Cursors

At my work place, cursors are banned in our SQL Server standards. In order to use a cursor, we have to prove that the performance of the cursor is better than processing the rows another way. It has happened, by the way, that we've proved the cursor to be the better option, but it's rare.

The preferred way of getting around cursors where I work, is to fetch the rows into a temporary table, often with an identity column as the key. We then loop through the rows in the temporary table using the identity (or other key) column to single out the next row to process, process the row, and move on to the next row by primary key.

Of course, it is implied in our policy that all set-based options have been exhausted as a means to process these rows. Set-based operations are by far the preferred method of processing data and therefore the number one alternative to cursors. Sometimes, however, it's just not possible.

The introduction of Common Table Expressions (CTEs) in SQL Server 2005 gives developers more flexibility in working around cursors. CTEs, like derived tables, allow you to express a temporary result set within a single SELECT, INSERT, UPDATE, or DELETE. CTEs, however, can be referenced multiple times within the SQL operation.

Along those same lines, correlated sub-queries should be considered as a way to provide a similar kind of row-by-row processing. The difference being that the correlated sub-query returns matches for each of the outer rows being operated on instead of finding all the "inner" rows via a cursor and scrolling through them to process the "outer" data.

There are other methods that may work well for your situation. There is no one option that covers all needs. These are just some of the more popular solutions.

Conclusion

Cursors are an effective means of accomplishing row-by-row processing. However, there are some inherent performance issues. It is important to understand how your cursor is affecting the underlying tables, SQL Server resources, and concurrency. While there are options available to tune cursors, often times alternatives such as set-based operations or while loops are actually better performing.

For More Information

MSDN: DECLARE CURSOR
MSDN: Cursor Performance
MSDN: Cursors
MSDN: Cursor Types (Database Engine)

该数据集通过合成方式模拟了多种发动机在运行过程中的传感器监测数据,旨在构建一个用于机械系统故障检测的基准资源,特别适用于汽车领域的诊断分析。数据按固定时间间隔采集,涵盖了发动机性能指标、异常状态以及工作模式等多维度信息。 时间戳:数据类型为日期时间,记录了每个数据点的采集时刻。序列起始于2024年12月24日10:00,并以5分钟为间隔持续生成,体现了对发动机运行状态的连续监测。 温度(摄氏度):以浮点数形式记录发动机的温度读数。其数值范围通常处于60至120摄氏度之间,反映了发动机在常规工况下的典型温度区间。 转速(转/分钟):以浮点数表示发动机曲轴的旋转速度。该参数在1000至4000转/分钟的范围内随机生成,符合多数发动机在正常运转时的转速特征。 燃油效率(公里/升):浮点型变量,用于衡量发动机的燃料利用效能,即每升燃料所能支持的行驶里程。其取值范围设定在15至30公里/升之间。 振动_X、振动_Y、振动_Z:这三个浮点数列分别记录了发动机在三维空间坐标系中各轴向的振动强度。测量值标准化至0到1的标度,较高的数值通常暗示存在异常振动,可能与潜在的机械故障相关。 扭矩(牛·米):以浮点数表征发动机输出的旋转力矩,数值区间为50至200牛·米,体现了发动机的负载能力。 功率输出(千瓦):浮点型变量,描述发动机单位时间内做功的速率,取值范围为20至100千瓦。 故障状态:整型分类变量,用于标识发动机的异常程度,共分为四个等级:0代表正常状态,1表示轻微故障,2对应中等故障,3指示严重故障。该列作为分类任务的目标变量,支持基于传感器数据预测故障等级。 运行模式:字符串类型变量,描述发动机当前的工作状态,主要包括:怠速(发动机运转但无负载)、巡航(发动机在常规负载下平稳运行)、重载(发动机承受高负荷或高压工况)。 数据集整体包含1000条记录,每条记录对应特定时刻的发动机性能快照。其中故障状态涵盖从正常到严重故障的四级分类,有助于训练模型实现故障预测与诊断。所有数据均为合成生成,旨在模拟真实的发动机性能变化与典型故障场景,所包含的温度、转速、燃油效率、振动、扭矩及功率输出等关键传感指标,均为影响发动机故障判定的重要因素。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值