SQL Server 游标

游标
游标是邪恶的!在关系数据库中, 查询是面向集合的,而游标打破了这个规则, 游标是面向记录的(行),正确的面向集合的思维方式是这样的
SQL Server 游标_第1张图片

 

而对于游标来说
SQL Server 游标_第2张图片

 

 

这也就是为什么游标是邪恶的,同样的, 在性能上,游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源,更多的代码量
从游标读取数据的方式不难看出为什么占用更多的资源,比如:当你从ATM里一次取1000效率高呢?还是10次取100快?

 

既然游标是邪恶的,为什么我们还要学习游标呢?
存在即合理,就像前面说的,IN与NOT IN是无视索引的,会引发查询一系列的隐藏问题,但是就是有它自己的用处。当我们穷尽了WHILE和子查询或者其他条件仍然无法完成查询的效果,就可以使用游标来实现

 

T-SQL中游标的生命周期以及实现
游标由5个部分组成
1.定义一个游标
在T-SQL,定义一个游标可以是很简单的,也可以是复杂的,取决于游标的参数,而游标的参数设置决定了你对游标原理的理解程度
游标其实可以理解为一个定义在特定 数据集上的指针(如果对数据集的概念不理解可以看上一篇文章),我们可以控制这个指针遍历数据集,或者指向特定行,所以游标是在以SELECT开始的数据集上的
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL](作用域)
        [FORWARD_ONLY | SCROLL](方向)
        [STATIC | KEYSET | DYNAMIC | FAST_FORWARD](类型)
        [READ_ONLY | SCROLL_LOCK | OPTIMISTIC]
        [TYPE_WARNING]
        FOR SELECT col1,col2 FROM table_name

下面就仔细讲一下这句语句的意义

游标分为全局游标和局部游标,对于局部游标来说,遵循T-SQL变量的定义方法(变量的定义可以参考前面文章),局部游标变量支持两种方式赋值,定义时候赋值,或者先定义后赋值,定义时要在游标名前面加‘@’,如果定义全局游标,就不用加‘@’,只支持定义时直接赋值

SQL Server 游标_第3张图片

下面讲参数的选择:

LOCAL和GLOBAL二选一

LOCAL意味着游标的s生存周期只在批处理,函数或者存储过程中可见,类似局部变量,而GLOBAL在在整个会话窗口中可见,全局有效

如果不指定作用域,默认为GLOBAL

SQL Server 游标_第4张图片

FORWARD_ONLY和SCROLL二选一

FORWARD_ONLY意味着游标只能从数据集开始的地方向数据集结束的地方的方向读取,FETCH NEXT 为唯一选项。而SCROLL支持游标在定义的数据集中向任何方向或者任何位置移动。不加参数则默认为FORWARD_ONLY

 SQL Server 游标_第5张图片

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 cursor_name即可以打开游标

3.读取游标数据

游标的使用分为两部分,一部分是操作游标在数据集内的指向,另一部分是将游标所指向的部分行或者全部行进行操作

6种移动方式:第一行(FIRST),最后一行(LAST),下一行(NEXT),上一行(PRIOR),直接跳向某行(ABSOLUTE n),相对于目前行的第几行(RELATIVE n)

SQL Server 游标_第6张图片

游标经常会与全局变量@@FETCH_STATUS与WHILE循环配合使用,以达到遍历游标所在的数据集的目的

SQL Server 游标_第7张图片

4.关闭游标
使用完游标后要关闭游标:CLOSE cursor_name
5.释放游标
当游标不再使用了一定要释放游标:DEALLOCATE cursor_name
全局变量@@FETCH_STATUS
每执行一个FETCH后,都会返回一次@@FETCH_STATUS状态值,判断FETCH是否执行成功
0:表示成功执行FETCH
-1:表示FETCH语句失败,例如移动指针使其超出的结果集
-2:表示被提取的行不存在
建议
  • 如果能不用游标就别用,游标永远是无奈下的选择,是一种非常邪恶的存在,面向记录的特性会比面向集合的特性慢上很多倍
  • 用完一定要关闭与释放
  • 有大量数据的时候不要用游标
  • 尽量不要用游标更新数据
  • 尽量不要使用INSENSITIVE,STATIC和KEYSET这些参数定义游标,因为占用了其他空间 
  • 如果可以,尽量使用FAST_FORWARD关键字定义游标
  • 如果只对数据进行读取,当读取只用到FETCH NEXTx选项,最好使用FORWARD_ONLY参数

 

 

 

你可能感兴趣的:(SQL,Server,sql,数据库,sqlserver)