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本身提供了一些存储过程,用于管理有关数据库和用户的信息. 用户存 ...
随机推荐
- (转) intellij idea部署web项目时的位置(Tomcat)
这篇文章说的比较好: 原文地址:https://blog.csdn.net/zmx729618/article/details/78340566 1.当你项目启动的时候console能看到项目运行的位 ...
- 类HashMap
/* * Map集合的特点 * 将键映射值的对象,一个映射不能包含重复的值:每个键最多只能映射到一个值 * * Map集合和Collection集合的区别? * Map集合存储元素是成对出现的,Map ...
- Mac 10.14 下为php 安装xdebug 并让vscode支持
安装Xdebug 寻找对应php版本的xdebug版本 先将info输出到一个文件 php -i > info.txt 打开info.txt 复制所有内容 打开寻找合适xdebug的页面http ...
- Java ——日期时间 日期时间相关类 随机数 定义类属性时建议使用引用数据类型
本节重点思维导图 Date对象创建 两个构造函数: Date() ----使用当前日期和时间来初始化对象 Date(long millisec) -----接收一个参数,该参数是从1970年1月1日起 ...
- IE浏览器下用JS创建文件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 使用Vsftpd服务(匿名访问模式、本地用户模式)
FTP协议占用两个端口号: 21端口:命令控制,用于接收客户端执行的FTP命令. 20端口:数据传输,用于上传.下载文件数据.. FTP数据传输的类型: 主动模式:FTP服务端主动向FTP客户端发起连 ...
- [Bzoj2004][Hnoi2010]Bus 公交线路(状压dp&&矩阵加速)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2004 看了很多大佬的博客才理解了这道题,菜到安详QAQ 在不考虑优化的情况下,先推$dp ...
- Django之模板(T)
一, 常用语法 Django模板中只需要记两种特殊符号: {{ }}和 {% %} {{ }}表示变量,在模板渲染的时候替换成值,{% %}表示逻辑相关的操作. 一, 变量 语法: {{ 变量名 }} ...
- JVM — 类加载机制
1. 引言 java 类被虚拟机编译之后成为一个 Class 的字节码文件,该字节码文件中包含各种描述信息,最终都需要加载到虚拟机中之后才能运行和使用.那么虚拟机是如何加载这些 Class 文件?Cl ...
- 问题 K: WaWa的难题
问题 K: WaWa的难题 时间限制: 1 Sec 内存限制: 128 MB提交: 570 解决: 125[提交] [状态] [命题人:jsu_admin] 题目描述 HaHa和WaWa是好朋友, ...