cursor or set-based
标题可能和正文不太相符。我主要是记录工作中遇到使用游标的语句改成普通set-based operation,执行时间快了很多。
1、游标语句
declare @startDate dateTime
declare @endDate dateTime
set @startDate = convert(varchar(10),dateAdd(day,-1,getDate()),120)
set @endDate = convert(varchar(10),getDate(),120) declare @serverID int
declare loop_cursor cursor for
select distinct serverID from OnLineUserStat with(nolock)
where realTime between @startDate and @endDate
open loop_cursor
fetch next from loop_cursor into @serverID
while @@fetch_status = 0
begin
declare @loopTime dateTime
set @loopTime = @startDate
while @loopTime < @endDate
begin
insert into OnLineUserStat2
(serverID,kindID,OnLineUserCount,playUserCount,RoomName,StatTime,RealTime)
select top 1 serverID,kindID,OnLineUserCount,playUserCount,RoomName,@looptime,RealTime
from OnLineUserStat with(nolock)
where serverID = @serverID and statTime <= @loopTime
and dateDiff(minute,statTime,@loopTime) <= 7
order by statTime desc set @loopTime = dateAdd(minute,5,@loopTime)
end
fetch next from loop_cursor into @serverID
end
close loop_cursor
deallocate loop_cursor
OnLineUserStat表的记录如下:
OnLineUserStat2表的记录如下:
游标的目的是针对每一个房间,创建时间基准(每5分钟一个基准,一天总计288个),针对各个时间基准获取前7分钟内最近的记录。
每天的distinct ServerID个数约400,每个房间创建288个时间基准,每天insert数量约11万。游标语句在服务器上执行耗时17分钟。
2、set-based语句
create table #date(StandTime datetime)
declare @StandTime datetime
select @StandTime=convert(varchar(10),getdate()-1,112)
while @StandTime<convert(varchar(10),getdate(),112)
begin
insert into #date(StandTime) values(@StandTime)
set @StandTime=dateadd(mi,5,@StandTime)
end ;with a as(
select a.StandTime,b.*
,row_number() over(partition by b.ServerID,a.StandTime order by b.ServerID,b.RealTime desc) rankid from #date a
,LK78DB.dbo.OnLineUserStat b with(nolock)
where b.RealTime<=a.StandTime
and b.RealTime>=dateadd(mi,-7,a.StandTime)
)
insert into OnLineUserStat2
select serverID,kindID,OnLineUserCount,playUserCount,RoomName,StandTime as StatTime,RealTime
from a
where rankid=1 drop table #date
借助于临时表生成所有时间基准,然后关联临时表与OnLineUserStat,得到最终结果。此语句耗时3秒。
3、计划对比
至于两者消耗为什么差别这么大,我们来看下它们的主体语句对应的执行计划,为了演示方便这里仅取三条数据。
3.1、while对应的执行计划


3.2、set-based对应的执行计划


while的逻辑读远高于set-based,while外面再套层cursor,需要repeats更多。
实际while语句的消耗在键查找,注意OnLineUserStat表的记录,StatTime和RealTime相同!可将where条件及order by更改为RealTime

相比第一个语句,逻辑读低了很多。。。
4、验证数据
例中将cursor+while修改为set-based,变动还是比较大。修改后我们需要验证语句与修改前是等效的,即修改后得到的结果与修改前得到的结果相同,不然修改的意义何在。
4.1、逻辑检查
语句逻辑是否满足原始需求
4.2、结果对比
最终会将数据写入到数据表,我们可以针对某一天的数据使用TableDiff对比是否存在差异。
我是将要对比的数据导入本地,当然可以直接带上源和目标的用户和密码对比数据(详细参数请参考 TableDiff /?) ,本例使用下面的命令对比
cd C:\Program Files\Microsoft SQL Server\\COM
TableDiff -sourceserver "127.0.0.1,7777" -sourcedatabase "Test" -sourcetable "OnLineUserStat2_17" -destinationserver "127.0.0.1,7777" -destinationdatabase "Test" -destinationtable "OnLineUserStat2_204" -f "C:\diff"

结果显示源和目标是相同的(identical)
4.3、TableDiff补充
如果对比的两表数据不一致,会产生什么样的结果?为了模拟这种情况,首先更新源OnLineUserStat2_17前7行数据,使其与OnLineUserStat2_204不一致,然后运行对比代码
结果显示有7处不同,并且生成应用目标的sql脚本(C:\diff.sql)
在对应Host->Database执行diff.sql就能让目标与源保持一致(以源为标准)
如果对比的两表没有自增列,会产生什么样的结果?为了模拟这种情况,删除ID自增字段,然后运行对比代码
也就是说对比的两表至少需要有唯一标识字段,否则无法分辨对比什么数据。
cursor or set-based的更多相关文章
- SQL CURSOR
SET NOCOUNT ON; DECLARE @vendor_id int, @vendor_name nvarchar(50), @message varchar(80), @produc ...
- Use Cursor
declare : CURSOR cursor_name IS select_statement ; open : OPEN cursor_name if the query returns no r ...
- Rolling Cursor Invalidations with DBMS_STATS.AUTO_INVALIDATE (文档 ID 557661.1)
Rolling Cursor Invalidations with DBMS_STATS.AUTO_INVALIDATE (文档 ID 557661.1) 转到底部 In this Documen ...
- Cursor: Pin S Wait On X In The Top 5 Wait Events
Wait Events , Posted in: Technical Track Tags: Group Blog Posts, Oracle, Technical Blog Lately, wait ...
- DECLARE CURSOR (Transact-SQL)
Defines the attributes of a Transact-SQL server cursor, such as its scrolling behavior and the query ...
- Resource Access Based on Multiple Credentials
A collection of multiple user credentials each associated with one of multiple different users is ob ...
- Oracle 11g 新特性 -- 自适应游标共享(Adaptive Cursor Sharing: ACS) 说明(转载)
一.自适应游标共享(Adaptive Cursor Sharing) 说明 1.1 ACS概述绑定变量使Oracle DB 可以为多条SQL 语句共享单个游标,以减少分析SQL 语句所使用的共享内存量 ...
- Create a cursor from hardcoded array instead of DB
https://stackoverflow.com/questions/18290864/create-a-cursor-from-hardcoded-array-instead-of-db Crea ...
- 自定义鼠标光标cursor
通过css属性 Cursor:url()自定义鼠标光标. {cursor:url('图标路径'),default;} url是自定义鼠标图标路径 default指的是定义默认的光标(通常是一个箭头), ...
- 苹果手机不支持click文字 需要添加 cursor:pointer 才能 识别可以点击
给一个div 绑定一个 click事件, 苹果手机会识别不了,必须添加一个 cursor:pointer 才能 识别可以点击.安卓正常识别.
随机推荐
- Angular.element和$document的使用方法分析,代替jquery
AngularJs是不直接操作DOM的,但是在平时的开发当中,我们有的时候还是需要操作一些DOM的,如果使用原生的JS的话操作过于麻烦,所以大家一般都是使用jQuery,jQuery虽然好用,但是An ...
- 【leetcode】Two Sum
题目简述: Given an array of integers, find two numbers such that they add up to a specific target number ...
- android 修改 SwitchPreferenceCompat 高度,内边距,字体大小
public class FontSizeSwitchPreferenceCompat extends SwitchPreferenceCompat { private Context mContex ...
- 我的jQuery源码读后感-jquery1.11.x 集成了 AMD
jquery1.11.x 集成了 AMD AMD 加入到了 jQuery, jQuery 把源码切分成各个逻辑模块. ready 整合成依赖 Deferred 的模块. 有些模块被切分成一些更加利于维 ...
- 【BZOJ】3993: [SDOI2015]星际战争
题意 \(m\)个人\(n\)个物品,第\(i\)个物品生命值为\(A_i\),第\(i\)个人每秒可以减少一个物品\(B_i\)的生命值,给出一个\(m \times n\)的矩阵,如果\(i\)行 ...
- Java_类的热替换
转自:http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/#ibm-pcon Java ClassLoader 技术剖析 在本文中,我们 ...
- IOS ReactiveCocoa
一 前提: 在iOS开发过程中,当某些事件响应时,需处理的某些业务逻辑 Eg. 按钮点击:action ScrollView滚动:delegate 属性值改变:KVO ReactiveCocoa为事件 ...
- Hibernate 二级缓存的配置及使用_EhCache
大多数的应用程序中都会添加缓存模块,以减少数据库访问次数,同时增加响应速度.下面介绍一下hibernate的二级缓存.默认情况下hibernate的二级缓存是不开启的,我们需要手动配置并启用. 注: ...
- 文本编辑器VIM/VI
vim/vi 功能强大全屏文本编辑器.主要是建立,编辑,显示文本. www.vim.org 构建shell脚本 :set number 使文件出现行号 a 光标后附件文件 i在光标前插入文 ...
- Android学习笔记之 android:collapseColumns ,android:shrinkColumns 和stretchColumns
摘自:http://blog.csdn.net/sjf0115/article/details/7213565/ TableLayout是一个使用复杂的布局,最简单的用法就仅仅是拖拉控件做出个界面,但 ...