在编写SQL批处理或存储过程代码的过程中,经常会碰到有些业务逻辑的处理,需要对满足条件的数据记录逐行进行处理,这个时候,大家首先想到的方案大部分是用“游标”进行处理。

  举个例子,在订单管理系统中,客服需要对订单日期为2012-09-01的销售订单进行某个批量操作,比如批量发货操作,后台业务逻辑处理时,需要对满足条件的订单记录进行逐行处理。

  我首先是采用“游标”编写的业务逻辑存储过程,SQL代码可以如下:

游标
DECLARE @ORDERID VARCHAR(30) -- 声明局部游标:从订单数据表获取订单日期为2012-09-01,订单类型为Sales的订单编号
DECLARE CURSOR_ORDER CURSOR LOCAL FOR
SELECT ORDERID FROM ORDERHD H WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales' -- 打开游标
OPEN CURSOR_ORDER
FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID
WHILE @@FETCH_STATUS = 0
BEGIN /*
此处编写对当前行数据的业务逻辑处理代码
*/ -- 得到下一条记录
FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID
END -- 关闭游标
CLOSE CURSOR_ORDER
-- 释放游标
DEALLOCATE CURSOR_ORDER

功能是实现了,但是客服在实际使用过程中,经常反馈批量操作效率太慢,需要等待较长时间才能完成操作。经过测试发现,速度慢在游标逐行处理过程中,当需要处理的记录数较大,而且游标处理位于数据库事务内时,速度非常慢。

  那么,有什么方法可以解决这个处理速度慢的问题吗?

  经不断的尝试,终于找到一个方法,那就是用WHILE循环来进行逐行数据处理。首先将需要处理的数据记录获取到一个临时表(此临时表包括2个重要字段:REFID - 记录行号,DealFlg:行处理标识,用1/0标识行是否已处理),然后WHILE循环对临时表进行逐行处理,SQL代码如下:

While 循环
DECLARE @REFID INT
, @ORDERID VARCHAR(30) -- 获取待处理的数据记录到临时表
-- 字段说明:REFID:记录行号 / DealFlg:行处理标识
SELECT REFID = IDENTITY(INT , 1, 1), DealFlg = 0, ORDERID
INTO #Temp_Lists
FROM ORDERHD
WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales' -- 获取临时表数据的最小行号
SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0 -- 若最小行号不为空(有需要处理的数据)
WHILE @REFID IS NOT NULL
BEGIN -- 获取当前处理行的信息
SELECT @ORDERID = ORDERID FROM #Temp_Lists WHERE REFID = @REFID /*
此处编写对当前行数据的业务逻辑处理代码
*/ -- 标识当前行已处理完毕
UPDATE #Temp_Lists SET DealFlg = 1 WHERE REFID = @REFID -- 选择下一行号
SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0 AND REFID > @REFID END

经过这样对原存储过程进行修正后,批量操作速度得到显著提升。

  有兴趣的朋友,可以尝试使用这个方法替代游标,对比2种方案的处理效率。

在编写SQL批处理或存储过程代码的过程中,经常会碰到有些业务逻辑的处理,需要对满足条件的数据记录逐行进行处理,这个时候,大家首先想到的方案大部分是用“游标”进行处理。

  举个例子,在订单管理系统中,客服需要对订单日期为2012-09-01的销售订单进行某个批量操作,比如批量发货操作,后台业务逻辑处理时,需要对满足条件的订单记录进行逐行处理。

  我首先是采用“游标”编写的业务逻辑存储过程,SQL代码可以如下:

 1 DECLARE @ORDERID    VARCHAR(30)
2
3 -- 声明局部游标:从订单数据表获取订单日期为2012-09-01,订单类型为Sales的订单编号
4 DECLARE CURSOR_ORDER CURSOR LOCAL FOR
5 SELECT ORDERID FROM ORDERHD H WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales'
6
7 -- 打开游标
8 OPEN CURSOR_ORDER
9 FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID
10 WHILE @@FETCH_STATUS = 0
11 BEGIN
12
13 /*
14 此处编写对当前行数据的业务逻辑处理代码
15 */
16
17 -- 得到下一条记录
18 FETCH NEXT FROM CURSOR_ORDER INTO @ORDERID
19 END
20
21 -- 关闭游标
22 CLOSE CURSOR_ORDER
23 -- 释放游标
24 DEALLOCATE CURSOR_ORDER

  功能是实现了,但是客服在实际使用过程中,经常反馈批量操作效率太慢,需要等待较长时间才能完成操作。经过测试发现,速度慢在游标逐行处理过程中,当需要处理的记录数较大,而且游标处理位于数据库事务内时,速度非常慢。

  那么,有什么方法可以解决这个处理速度慢的问题吗?

  经不断的尝试,终于找到一个方法,那就是用WHILE循环来进行逐行数据处理。首先将需要处理的数据记录获取到一个临时表(此临时表包括2个重要字段:REFID - 记录行号,DealFlg:行处理标识,用1/0标识行是否已处理),然后WHILE循环对临时表进行逐行处理,SQL代码如下:

 1 DECLARE   @REFID        INT
2 , @ORDERID VARCHAR(30)
3
4 -- 获取待处理的数据记录到临时表
5 -- 字段说明:REFID:记录行号 / DealFlg:行处理标识
6 SELECT REFID = IDENTITY(INT , 1, 1), DealFlg = 0, ORDERID
7 INTO #Temp_Lists
8 FROM ORDERHD
9 WHERE ORDERDATE = '2012-09-01' AND H.ORDERTYPE = 'Sales'
10
11 -- 获取临时表数据的最小行号
12 SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0
13
14 -- 若最小行号不为空(有需要处理的数据)
15 WHILE @REFID IS NOT NULL
16 BEGIN
17
18 -- 获取当前处理行的信息
19 SELECT @ORDERID = ORDERID FROM #Temp_Lists WHERE REFID = @REFID
20
21 /*
22 此处编写对当前行数据的业务逻辑处理代码
23 */
24
25 -- 标识当前行已处理完毕
26 UPDATE #Temp_Lists SET DealFlg = 1 WHERE REFID = @REFID
27
28 -- 选择下一行号
29 SELECT @REFID = MIN(REFID) FROM #Temp_Lists WHERE DealFlg = 0 AND REFID > @REFID
30
31 END

改写方法2

declare @msg varchar(1000)
declare @refuseno varchar(30)
while 1=1
begin
select top 1 @refuseno = refuseno from #user_data
if @@rowcount = 0 break
/*
业务处理代码
*/
if @@error <> 0
begin
set @msg = '业务单转失败' + @refuseno
rollback
raiserror(@msg,16,1)
return
end
delete from #user_data where refuseno = @refuseno
end drop table #user_data

  

经过这样对原存储过程进行修正后,批量操作速度得到显著提升。

  有兴趣的朋友,可以尝试使用这个方法替代游标,对比2种方案的处理效率。

SQL Server 中用While循环替代游标Cursor的解决方案的更多相关文章

  1. [转]SQL Server中用While循环替代游标(Cursor)的解决方案

    本文转自:https://www.cnblogs.com/SunnyZhu/p/5719184.html By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行 ...

  2. SQL Server中用While循环替代游标(Cursor)的解决方案

    By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行数据分别需要多长时间. 一.游标. 首先我们填充一个表,用优雅的递归方式填充. ,) ) ;with ct ...

  3. SQL Server 内存泄露(memory leak)——游标导致的内存问题

    原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...

  4. 在SQL Server中用好模糊查询指令LIKE

    简介:like在sql中的使用 在SQL Server中用好模糊查询指令LIKE 查询是SQL Server中重要的功能,而在查询中将Like用上,可以搜索到一些意想不到的结果和效果,like的神奇之 ...

  5. 在SQL Server中用好模糊查询指令LIKE (转载)

    like在sql中的使用:在SQL Server中用好模糊查询指令LIKE:查询是SQL Server中重要的功能,而在查询中将Like用上,可以搜索到一些意想不到的结果和效果,like的神奇 一.一 ...

  6. SQL Server阻止了对组件xp_cmdshell过程的解决方案

    使用SQL tools连接sqlserver时候出现以下问题: SQL Server阻止了对组件xp_cmdshell过程的解决方案错误描述:SQL Server阻止了对组件‘xp_cmdshell’ ...

  7. SQL Server阻止了对组件xp_cmdshell过程的解决方案 分类: SQL Server 2015-03-05 08:31 305人阅读 评论(0) 收藏

    SQL Server阻止了对组件xp_cmdshell过程的解决方案 错误描述:SQL Server阻止了对组件'xp_cmdshell'的过程'sys.xp_cmdshell'的访问.因为此组件已作 ...

  8. SQL Server 事务、异常和游标

    转自:http://www.cnblogs.com/hoojo/archive/2011/07/19/2110325.html Ø 事务 在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整 ...

  9. SQL Server 存储过程、触发器、游标

    存储过程 1.存储过程是事先编好的.存储在数据库中的程序,这些程序用来完成对数据库的指定操作. 2.系统存储过程: SQL Server本身提供了一些存储过程,用于管理有关数据库和用户的信息. 用户存 ...

随机推荐

  1. 003-Web Worker工作线程

    一.关于Web Worker工作线程 HTML5几个优势特性里,就包括了Web Worker,这货可以了解为多线程,正常形况下,浏览器执行某段程序的时候会阻塞直到运行结束后在恢复到正常状态,而HTML ...

  2. 阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_11_反射_案例

    student定义sleep方法 用反射+配置文件 定义配置文件 src下new file.新建 加载配置文件.Properties里面有一个load方法,可以加载.properties结尾的配置文件 ...

  3. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_08 Map集合_9_Hashtable集合

    是最早期的双列集合 同步就表示是单线程 value也不允许为空

  4. postman+newman+jenkins接口自动化

    postman用来做接口测试非常方便,接口较多时,则可以实现接口自动化 目录 1.环境准备 2.本机调试脚本 3.集成jenkins 1.环境准备 1.1安装nodejs6.0+ 安装nodejs6. ...

  5. fastdfs集群安装过程_学习笔记

    最终效果 初始化为6个节点 在/usr/local/software 目录下上传需要用到tar包,分别在各个节点上传 使用scp 将本地software目录复制到其他节点上 73.74为 tracke ...

  6. GCD and LCM HDU 4497 数论

    GCD and LCM HDU 4497 数论 题意 给你三个数x,y,z的最大公约数G和最小公倍数L,问你三个数字一共有几种可能.注意123和321算两种情况. 解题思路 L代表LCM,G代表GCD ...

  7. 动画可以暂停animation-play-state

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. window.onload后跟函数 和跟函数名的区别【window.onload = asd() 和 window.onload = asd 】

    window.onload:页面加载完毕执行[DOM tree + 外部图片 + 资源] <script> function asd(){ return 10; } window.onlo ...

  9. Eclipse打包可执行jar包操作步骤

    1.右键点击工程,选择Export…,进入页面 2.弹出对话框,选择Java->Runnable JAR file ,点击Next>,页面显示jar包的输出路径,配置为jmeter的/li ...

  10. Nodejs中request出现ESOCKETTIMEDOUT解决方案

    做需求的时候,使用Nodejs的request批量请求某一个接口,由于接口超时,出现 ESOCKETTIMEDOUT,程序中断 为了让程序遇到 ESOCKETTIMEDOUT 之后能够继续执行下去,需 ...