概述
游标是邪恶的!
在关系数据库中,我们对于查询的思考是面向集合的。而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服。
正常面向集合的思维方式是:
而对于游标来说:
这也是为什么游标是邪恶的,它会使开发人员变懒,懒得去想用面向集合的查询方式实现某些功能.
同样的,在性能上,游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源,当然还有更多的代码量……
从游标对数据库的读取方式来说,不难看出游标为什么占用更多的资源,打个比方:
当你从ATM取钱的时候,是一次取1000效率更高呢,还是取10次100?
既然游标这么“邪恶”,为什么还要学习游标
我个人认为存在既是合理.归结来说,学习游标原因我归纳为以下2点
1.现存系统有一些游标,我们查询必须通过游标来实现
2.作为一个备用方式,当我们穷尽了while循环,子查询,临时表,表变量,自建函数或其他方式扔来无法实现某些查询的时候,使用游标实现.
T-SQL中游标的生命周期以及实现
在T-SQL中,游标的生命周期由5部分组成
1.定义一个游标在T-SQL中,定义一个游标可以是非常简单,也可以相对复杂,取决于游标的参数.而游标的参数设置取决于你对游标原理的了解程度.
游标其实可以理解成一个定义在特定数据集上的指针,我们可以控制这个指针遍历数据集,或者仅仅是指向特定的行,所以游标是定义在以Select开始的数据集上的:
T-SQL中的游标定义在MSDN中如下:
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] [ FORWARD_ONLY | SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] [ TYPE_WARNING ] FOR select_statement [ FOR UPDATE [ OF column_name [ ,...n ] ] ][;]
看起来很让人头痛是吧.下面仔细讲一下如何定义游标:
游标分为游标类型和游标变量,对于游标变量来说,遵循T-SQL变量的定义方法(啥,不知道T-SQL变量定义的规则?参考我前面的博文).游标变量支持两种方式赋值,定义时赋值和先定义后赋值,定义游标变量像定义其他局部变量一样,在游标前加”@”,注意,如果定义全局的游标,只支持定义时直接赋值,并且不能在游标名称前面加“@”,两种定义方式如下:
下面我们来看游标定义的参数:
LOCAL和GLOBAL二选一
LOCAL意味着游标的生存周期只在批处理或函数或存储过程中可见,而GLOBAL意味着游标对于特定连接作为上下文,全局内有效,例如:
如果不指定游标作用域,默认作用域为GLOBAL
FORWARD_ONLY 和 SCROLL 二选一
FORWARD_ONLY意味着游标只能从数据集开始向数据集结束的方向读取,FETCH NEXT是唯一的选项,而SCROLL支持游标在定义的数据集中向任何方向,或任何位置移动,如下图:
STATIC KEYSET DYNAMIC 和 FAST_FORWARD 四选一
这四个关键字是游标所在数据集所反应的表内数据和游标读取出的数据的关系
STATIC意味着,当游标被建立时,将会创建FOR后面的SELECT语句所包含数据集的副本存入tempdb数据库中,任何对于底层表内数据的更改不会影响到游标的内容.
DYNAMIC是和STATIC完全相反的选项,当底层数据库更改时,游标的内容也随之得到反映,在下一次fetch中,数据内容会随之改变
KEYSET可以理解为介于STATIC和DYNAMIC的折中方案。将游标所在结果集的唯一能确定每一行的主键存入tempdb,当结果集中任何行改变或者删除时,@@FETCH_STATUS会为-2,KEYSET无法探测新加入的数据
FAST_FORWARD可以理解成FORWARD_ONLY的优化版本.FORWARD_ONLY执行的是静态计划,而FAST_FORWARD是根据情况进行选择采用动态计划还是静态计划,大多数情况下FAST_FORWARD要比FORWARD_ONLY性能略好.
READ_ONLY SCROLL_LOCKS OPTIMISTIC 三选一 READ_ONLY意味着声明的游标只能读取数据,游标不能做任何更新操作
SCROLL_LOCKS是另一种极端,将读入游标的所有数据进行锁定,防止其他程序进行更改,以确保更新的绝对成功
OPTIMISTIC是相对比较好的一个选择,OPTIMISTIC不锁定任何数据,当需要在游标中更新数据时,如果底层表数据更新,则游标内数据更新不成功,如果,底层表数据未更新,则游标内表数据可以更新
2.打开游标
当定义完游标后,游标需要打开后使用,只有简单一行代码:
OPEN test_Cursor
注意,当全局游标和局部游标变量重名时,默认会打开局部变量游标
3.使用游标
游标的使用分为两部分,一部分是操作游标在数据集内的指向,另一部分是将游标所指向的行的部分或全部内容进行操作
只有支持6种移动选项,分别为到第一行(FIRST),最后一行(LAST),下一行(NEXT),上一行(PRIOR),直接跳到某行(ABSOLUTE(n)),相对于目前跳几行(RELATIVE(n)),例如:
对于未指定SCROLL选项的游标来说,只支持NEXT取值.
第一步操作完成后,就通过INTO关键字将这行的值传入局部变量:
比如下面代码:
游标经常会和全局变量@@FETCH_STATUS与WHILE循环来共同使用,以达到遍历游标所在数据集的目的,例如:
4.关闭游标
在游标使用完之后,一定要记得关闭,只需要一行代码:CLOSE+游标名称
CLOSE test_Cursor
5.释放游标
当游标不再需要被使用后,释放游标,只需要一行代码:DEALLOCATE+游标名称
DEALLOCATE test_Cursor
对于游标一些优化建议
总结
本文从游标的基本概念,到生命周期来谈游标。游标是非常邪恶的一种存在,使用游标经常会比使用面向集合的方法慢2-3倍,当游标定义在大数据量时,这个比例还会增加。如果可能,尽量使用while,子查询,临时表,函数,表变量等来替代游标,记住,游标永远只是你最后无奈之下的选择,而不是首选。
游标是邪恶的!
分类: T-SQL[转帖]SQL Server 10分钟理解游标
标签:方法 ros 了解 图片 比例 height glob eal 关系
小编还为您整理了以下内容,可能对您也有帮助:
SQL Server中的游标是什么意思?
①概念:游标(cursor)是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果。每个游标区都有一个名字。用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理
②特点:游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制
③作用:当需要逐条读取记录时可以用游标,相当于for循环,一次获取一条记录进行操作。当一组记录没有id字段时,此时用for循环不能够实现,而游标可以解决此问题(注:当数据量很大的时候不建议使用游标,因为游标处理处理数据比较慢)
SQL中的指针和游标怎么理解?
windows或DOS的“光标”不同,MS-SQL的游标是一种临时的数据库对象,既对可用来旋转储存在系统永久表中的数据行的副本,也可以指向储存在系统永久表中的数据行的指针。
游标为您提供了在逐行的基础上而不是一次处理整个结果集为基础的操作表中数据的方法。 1.如何使用游标 1)定义游标语句 Declare <游标名> Cursor For
2)创建游标语句 Open <游标名>
3)提取游标列值、移动记录指针 Fetch <列名列表> From <游标名> [Into <变量列表>]
4)使用@@Fetch_Status利用While循环处理游标中的行
5)删除游标并释放语句 Close <游标名>/Deallocate <游标名>
6)游标应用实例 --定义游标
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department into @DeptID,@DeptName
--创建游标
Open cur_Depart
--移动或提取列值
Fetch From cur_Depart into @DeptID,@DeptName
--利用循环处理游标中的列值
While @@Fetch_Status=0
Begin
Print @DeptID,@DeptName
Fetch From cur_Depart into @DeptID,@DeptName
End
--关闭/释放游标
Close cur_Depart
Deallocate cur_Depart2.语句的详细及注意 1)定义游标语句 Declare <游标名> [Insensitive] [Scroll] Cursor
For <Select 语句> [FOR {Read Only | Update [ OF <列名列表>]}] Insensitive DBMS创建查询结果集数据的临时副本(而不是使用直接引用数据库表中的真实数据行中的列)。游标是Read Only,也就是说不能修改其内容或底层表的内容; Scroll 指定游标支持通过使用任意Fetch 选项(First Last Prior Next Relative Absolute)选取它的任意行作为当前行。如果此项省略,则游标将只支持向下移动单行(即只支持游标的Fetch Next); Select语句 定义游标结果集的标准 SELECT 语句。在游标声明的 <Select语句>内不允许使用关键字 COMPUTE、COMPUTE BY、FOR BROWSE 和 INTO; Read Only 防止使用游标的用户通过更新数据或删除行改变游标的内容; Update 创建可更新游标且列出值能被更新的游标列。如果子句中列入了任意列,则只有被列入的列才能被更新。如果Declare Cursor语句中只指定的UPDATE(没有列名列表),则游标将允许更新它的任何或所有列。
Declare cur_Depart Cursor
For Select * From Department For Update OF cDeptID,cDeptName 2)提取游标列值、移动记录指针语句 Fetch [Next | Prior | First | Last | {Absolute <行号>} | {Relative <行号>}]
From <游标名> [Into <变量列表……>] 每次执行Fetch语句时,DBMS移到游标中的下一行并把游标中的列值获取到Into中列出的变量中。因此Fetch语句的Into子句中列出的变量必须与游标定义中Select 语句中的列表的类型与个数相对应; 仅当定义游标时使用Scroll参数时,才能使用Fetch语句的行定位参数(First Last Prior Next Relative Absolute);如果Fetch语句中不包括参数Next | Prior | First | Last,DBMS将执行默认的Fetch Next; Next 向下、向后移动一行(记录); Prior 向上、向前移动一行(记录); First 移动至结果集的第一行(记录); Last 移动至结果集的最后一行(记录); Absolute n 移动到结果集中的第n行。如果n是正值,DBMS从结果集的首部向后或向下移动至第n行;如果n是负数,则DBMS从结果集的底部向前或向上移动n行;
Fetch Absolute 2 From cur_Depart Into @DeptID,@DeptName Relative n 从指针的当前位置移动n行。如果n是正值,DBMS将行指针向后或向下移动至第n行;如果n是负数,则DBMS将行指针向前或向上移动n行;
Fetch Relative 2 From cur_Depart Into @DeptID,@DeptName 3)基于游标的定位DELETE/UPDATE语句 如果游标是可更新的(也就是说,在定义游标语句中不包括Read Only 参数),就可以用游标从游标数据的源表中DELETE/UPDATE行,即DELETE/UPDATE基于游标指针的当前位置的操作;
举例: --删除当前行的记录
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department into @DeptID,@DeptName
Open cur_Depart
Fetch From cur_Depart into @DeptID,@DeptName
Delete From Department Where CURRENT OF cur_Depart --更新当前行的内容
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department into @DeptID,@DeptName
Open cur_Depart
Fetch From cur_Depart into @DeptID,@DeptName
Update Department Set cDeptID=’2007’ + @DeptID Where CURRENT OF cur_Depart3.游标使用技巧及注意 1)利用Order By改变游标中行的顺序。此处应该注意的是,只有在查询的中Select 子句中出现的列才能作为Order by子句列,这一点与普通的Select语句不同;
2)当语句中使用了Order By子句后,将不能用游标来执行定位DELETE/UPDATE语句;如何解决这个问题,首先在原表上创建索引,在创建游标时指定使用此索引来实现;例如:
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department With INDEX(idx_ID)
For Update Of cDeptID,cDeptName
通过在From子句中增加With Index来实现利用索引对表的排序;
3)在游标中可以包含计算好的值作为列;
4)利用@@Cursor_Rows确定游标中的行数;
Sql中的游标是干嘛的
在数据库中,游标提供了一种对从表中检索出的数据进行操作的灵活手段。就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。
游标总是与一条SQL 选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。
游标关于数据库中的操作会对整个行集产生影响。由 SELECT 语句返回的行集包括所有满足该语句 WHERE 子句中条件的行。由语句所返回的这一完整的行集被称为结果集。
应用程序,特别是交互式联机应用程序,并不总能将整个结果集作为一个单元来有效地处理。这些应用程序需要一种机制以便每次处理一行或一部分行。游标就是提供这种机制的结果集扩展。
扩展资料:
游标通过以下方式扩展结果处理:
1.允许定位在结果集的特定行。
2.从结果集的当前位置检索一行或多行。
3.支持对结果集中当前位置的行进行数据修改。
4.为由其他用户对显示在结果集中的数据库数据所做的更改提供不同级别的可见性支持。
5.提供脚本、存储过程和触发器中使用的访问结果集中的数据的 Transact-SQL 语句。
参考资料来源:百度百科—游标