SQL Server 中用While循环替代游标Cursor的解决方案
在编写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的解决方案的更多相关文章
- [转]SQL Server中用While循环替代游标(Cursor)的解决方案
本文转自:https://www.cnblogs.com/SunnyZhu/p/5719184.html By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行 ...
- SQL Server中用While循环替代游标(Cursor)的解决方案
By行处理数据,推荐2种方式: 1.游标 2.While循环 我们来了解下这两种方案处理1w行数据分别需要多长时间. 一.游标. 首先我们填充一个表,用优雅的递归方式填充. ,) ) ;with ct ...
- SQL Server 内存泄露(memory leak)——游标导致的内存问题
原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...
- 在SQL Server中用好模糊查询指令LIKE
简介:like在sql中的使用 在SQL Server中用好模糊查询指令LIKE 查询是SQL Server中重要的功能,而在查询中将Like用上,可以搜索到一些意想不到的结果和效果,like的神奇之 ...
- 在SQL Server中用好模糊查询指令LIKE (转载)
like在sql中的使用:在SQL Server中用好模糊查询指令LIKE:查询是SQL Server中重要的功能,而在查询中将Like用上,可以搜索到一些意想不到的结果和效果,like的神奇 一.一 ...
- SQL Server阻止了对组件xp_cmdshell过程的解决方案
使用SQL tools连接sqlserver时候出现以下问题: SQL Server阻止了对组件xp_cmdshell过程的解决方案错误描述:SQL Server阻止了对组件‘xp_cmdshell’ ...
- SQL Server阻止了对组件xp_cmdshell过程的解决方案 分类: SQL Server 2015-03-05 08:31 305人阅读 评论(0) 收藏
SQL Server阻止了对组件xp_cmdshell过程的解决方案 错误描述:SQL Server阻止了对组件'xp_cmdshell'的过程'sys.xp_cmdshell'的访问.因为此组件已作 ...
- SQL Server 事务、异常和游标
转自:http://www.cnblogs.com/hoojo/archive/2011/07/19/2110325.html Ø 事务 在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整 ...
- SQL Server 存储过程、触发器、游标
存储过程 1.存储过程是事先编好的.存储在数据库中的程序,这些程序用来完成对数据库的指定操作. 2.系统存储过程: SQL Server本身提供了一些存储过程,用于管理有关数据库和用户的信息. 用户存 ...
随机推荐
- Week3 - 397. Integer Replacement
Week3 - 397. Integer Replacement 397.Integer Replacement - Medium Given a positive integer n and you ...
- 观察者模式(jdk实现)
1.定义 在对象中定义一对多的依赖,当一个对象改变状态,依赖它的对象会收到通知并更新. 2.实现 (主要通过jdk自己定义的观察者实现) 以气象站通知展示板为例子,当气象站收到的各种参数改变的时候 ...
- Java ——Number & Math 类 装箱 拆箱 代码块
本节重点思维导图 当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double 等 int a = 5000; float b = 13.65f; byte c = 0 ...
- 安全运维 - Windows系统应急响应
挖矿病毒应急 传播方式: 通过社工.钓鱼方式下载和运行了挖矿程序(邮件.IM等) 利用计算机系统远程代码执行漏洞下载.上传和执行挖矿程序. 利用i算计Web或第三方软件漏洞获取计算机权限,然后下载和执 ...
- 安全运维 - Windows系统攻击回溯
Windows应急事件 病毒.木马.蠕虫 Web服务器入侵事件或第三方服务入侵事件 系统入侵事件 网络攻击事件(DDOS.ARP.DNS劫持等) 通用排查思路 获知异常事件基本情况 发现主机异常现象的 ...
- Mac015--在Mac下安装使用Vagrant
网址:http://yansu.org/2014/04/10/install-vagrant-in-mac.html 一.安装Vagrant 下载地址在http://www.vagrantup.com ...
- 老技术记录-C#+SqlServer使用SqlDependency监听数据库表变化
开发环境: .net / C# (.net core理论上也可以) 数据库:MS SQL Server 2005 以上 (我用的sqlserver2012) 功能:SqlDependency提供了一种 ...
- Spring MVC-学习笔记(3)参数绑定注解、HttpMessageConverter<T>信息转换、jackson、fastjson、XML
1.参数绑定注解 1>@RequestParam: 用于将指定的请求参数赋值给方法中的指定参数.支持的属性: 2>@PathVariable:可以方便的获得URL中的动态参数,只支持一个属 ...
- Codeforces 1042C (贪心+模拟)
题面 传送门 分析 思路简单,但代码较复杂的贪心 分类讨论: 有0 负数有奇数个:将绝对值最小(实际最大)的负数和0全部乘到一起,最后删掉0 负数有偶数个:将0全部乘到一起,最后删掉0 没有0 负数有 ...
- CentOS 5.5编译安装lnmp
如果是安装Centos6.5记得Perl是必选的,否则无法安装VMWare Tools!!!!切记 如果出现make错误需要安装其他软件,装好后 make clean make install ...