这些天看了一篇微软官方发布的MS SQL Server2008性能问题处理及优化的英文文档,里面知识点介绍地很详细,在现实工作中也很实用,遂产生了想把它翻译一下的念头。翻译的过程,既可以帮助自己复习一下这些技术,也可以向其他还不熟悉这一块的朋友介绍一些新的知识,何乐而不为呢。只是这篇文章有点长,我会分成几篇随笔去介绍,所以,不光是对我耐性的考验,也是对你的考验哦!
--------------------------------------------
使用不当的游标
SQL Server 2005之前的版本只支持在一个连接中共存唯一一个活动。一个正在执行的查询或者正在有结果被返回给客户端都被认为是一个活动。在很多情况下,客户端应用可能需要从结果集中按行读取数据,然后把这些数据提交给其他的查询语句使用。这种需要使用默认的结果集是不能实现的,因为它可能有其它未决定的结果。一个通用的解决方案是改变连接属性,使用一个服务器端的游标。
当一个服务器端的游标被使用后,数据库客户端软件(OLE DB 支持和ODBC驱动)会显式地将客户端需求结果压缩进指定的扩展存储过程,比如sp_cursoropen或者sp_cursorfetch。这就是所谓的API cursor(与transact-SQL游标截然相反)。当用户执行查询时,查询内容会通过sp_cursoropen被传送至服务器端;从结果集中读取数据的请求会导致sp_cursorfetch引导服务器只返回一定数量的结果行。通过控制匹配的行数,ODBC驱动或者OLE DB支持会缓存一定的结果行。这样做避免了这样一种情况:服务器等待客户端读取传送过去的所有行。这样,服务器服务器就做好了去接受连接上的新请求的准备。
应用程序某一时刻打开一个游标并且读取一行(或者小数目的几行),很容易就会因为网络延迟出现瓶颈,尤其是在WAN环境。在一个拥有多个用户连接的快速网络环境里,运行多个游标的开销会变得很明显。因为多个游标都需要定位各自的结果集,预请求就会变得开销很大,比使用100个游标,但每个游标返回一行更高效的做法是使用一个单独的游标返回100行数据。
诊断
你可以使用下面的工具去诊断不当的游标使用。
Performance Monitor
通过查看SQL Server:Cursor Manager By Type- Cursor/sec计数器,你可以初步感受下系统中有多少正在被使用。系统的使用率很高是因为每秒钟有许多的小匹配数目的游标被使用。没有一个特殊的计数器可以列举出来取出的缓冲大小。
DMVs
你可以使用下面的查询去确定API cursor的连接(与transact-SQL游标截然相反)对应每行获取的缓冲大小。使用更大的获取缓冲会更高效,例如100行。
select * from sys.dm_exec_connections con cross apply sys.dm_exec_cursors(con.session_id) as cur where cur.fetch_buffer_size=1 and cur.properties like 'API%' --API cursor(Transaction-SQL cursors always have a fetch buffer of 1)
SQL Trace
使用一个包含PRC:Completed 事物类的trace去查找sp_cursorfetch语句。其中第四个参数会去限制返回过来的匹配结果行数。最大的返回行数会在对应的PRC:Starting事物类的输入参数中设置。
解决方案
--确定下是游标是否是最合适的手段去完成对应的需求,考虑下是否有其它的方案可以替代。
--在连接至SQL Server 2008时,考虑启用多活动结果集(MARS)。
--参照对应的文档,针对特定的API,为游标指定一个更大的匹配缓冲:
-ODBC: SQL_ATTR_ROW_ARRAY_SIZE
-OLE DB: IRowset::GetNextRows or IRowsetLocate::GetRowsAt