码迷,mamicode.com
首页 > 其他好文 > 详细

(3.7)常用知识-游标的取舍

时间:2018-06-06 22:12:44      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:事务   数据   https   集中   .net   本地   tps   logs   代码   

  概念:在逐条处理数据的时候,游标显得十分重要,特别是在处理每一条数据时,需要与其他过程交互的情况下,如果不用游标,那真是太好了。

本章不介绍游标的具体使用,

1.全局游标与本地游标

  (1)定义游标的语句中指定

  在定义游标时,可以使用global关键字将游标显式地定义为全局游标,使用local关键字将游标定义为本地。

  (2)通过数据库选项控制

  如果定义游标时,未使用golbal或者local关键字,则由数据库的cursor_default选项设置来确定定义游标的作用于。sql server 7.0以后就默认为FALSE。

 

2.用循环代替游标(用临时表/identity/row_number)

  (1)构建表数据

首先我们填充一个表,用优雅的递归方式填充。

技术分享图片
create table Orders(OrderID int,CostValue decimal(18,2) )

;with cte_temp
as
(
    select 1 as OrderID
    union all
    select OrderID+1 from cte_temp where OrderID<10000
)

insert into Orders(OrderID)
select OrderID from cte_temp option (maxrecursion 32767);
技术分享图片

  

  现在我们的订单表Orders有了一万条订单,但是CostValue还是NULL值。

  我们用游标的方式给每一条订单添加一个CostValue,耗时44s。

技术分享图片
--游标
DECLARE @OrderID int

DECLARE cursor_CostValue CURSOR FOR  SELECT OrderID FROM Orders
OPEN cursor_CostValue
FETCH NEXT FROM cursor_CostValue INTO @OrderID
WHILE @@FETCH_STATUS = 0
BEGIN
    UPDATE Orders SET CostValue = OrderID+100 WHERE OrderID = @OrderID
    FETCH NEXT FROM cursor_CostValue INTO @OrderID
END
CLOSE cursor_CostValue  
DEALLOCATE cursor_CostValue
技术分享图片

 

   (2)While循环(用事务把整个语句包裹起来,效率更高)

  将数据放在临时表中,然后操作临时表,最后更新回总表。耗时16s。

技术分享图片
DECLARE @RowID int
      
--    获取待处理的数据记录到临时表
--    字段说明:RowID:记录行号 / DealFlg:行处理标识
SELECT  RowID = IDENTITY(INT , 1, 1),DealFlg=0,OrderID,CostValue = 0
INTO #Tmp
FROM Orders
SELECT @RowID = MIN(RowID) FROM #Tmp WHERE DealFlg = 0
--    若最小行号不为空(有需要处理的数据)
WHILE @RowID IS NOT NULL
BEGIN
    UPDATE #Tmp SET DealFlg = 1,CostValue=OrderID+100 WHERE RowID = @RowID

    SELECT @RowID = MIN(RowID) FROM #Tmp WHERE DealFlg = 0
END
update O set O.CostValue=T.CostValue
from Orders O
    inner join #Tmp T on O.OrderID=T.OrderID
技术分享图片

 

  还有一种错误的While循环,即不把数据放在临时表中,直接操作本表,会大大增加耗时。

  因为多次调用本表,如果在生产环境,将是一个灾难。

 

技术分享图片
DECLARE @OrderID INT   
--表中OrderID最小的值
SELECT @OrderID = MIN(OrderID) FROM Orders where CostValue is null
WHILE @OrderID IS NOT NULL
BEGIN
    UPDATE Orders SET CostValue = OrderID+100 WHERE OrderID = @OrderID
    SELECT @OrderID = MIN(OrderID) FROM Orders where CostValue is null
END
技术分享图片

 

总结:游标之所以慢,原因有很多。

  (1)一条一条处理数据

  (2)每次使用都需要执行一次select

  (3)读写过多:我们知道,游标是按行处理的,把查出来的结果集中的每一行的值,写到某几个变量里去,再读取该变量的值,再进行比较处理.
一般说来,读写内存变量值是比较花时间的,因此,游标执行的效率由此而降低.

 

参考:

【1】游标为什么慢?:https://bbs.csdn.net/topics/380124885

【2】游标的详细语法:http://www.cnblogs.com/kissdodog/p/3161341.html

【3】用whlie代替游标:https://www.cnblogs.com/SunnyZhu/p/5719184.html

(3.7)常用知识-游标的取舍

标签:事务   数据   https   集中   .net   本地   tps   logs   代码   

原文地址:https://www.cnblogs.com/gered/p/9146386.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!