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)

本系统旨在构建一套面向高等院校的综合性教务管理平台,涵盖学生、教师及教务处三个核心角色的业务需求。系统设计着重于实现教学流程的规范化与数据处理的自动化,以提升日常教学管理工作的效率与准确性。 在面向学生的功能模块中,系统提供了课程选修服务,学生可依据培养方案选择相应课程,并生成个人专属的课表。成绩查询功能支持学生查阅个人各科目成绩,同时系统可自动计算并展示该课程的全班最高分、平均分、最低分以及学生在班级内的成绩排名。 教师端功能主要围绕课程与成绩管理展开。教师可发起课程设置申请,提交包括课程编码、课程名称、学分学时、课程概述在内的新课程信息,亦可对已开设课程的信息进行更新或撤销。在课程管理方面,教师具备录入所授课程期末考试成绩的权限,并可导出选修该课程的学生名单。 教务处作为管理中枢,拥有课程审批与教学统筹两大核心职能。课程设置审批模块负责处理教师提交的课程申请,管理员可根据教学计划与资源情况进行审核批复。教学安排模块则负责全局管控,包括管理所有学生的选课最终结果、生成包含学号、姓名、课程及成绩的正式成绩单,并能基于选课与成绩数据,统计各门课程的实际选课人数、最高分、最低分、平均分以及成绩合格的学生数量。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值