|
【赛迪网-it技术报道】游标类型产生的数据检索问题:
现象:
在将数据库兼容的级别从80改到90以后, 下文中的游标循环不出数据, 单独select却会有结果:
declare mycursor cursor local read_only
for
select
col1
from tbname with(nolock)
where name like 'snet%'
and b_key in(
select top(100)
keyid
from tbmaster with(nolock)
where date >= '01/01/2007'
and date < '02/01/2007')
open mycursor
fetch next from mycursor
while (@@fetch_status=0)
begin
fetch next from mycursor
end
close mycursor
deallocate mycursor
原因:
游标类型的问题。
参照以上的定义, 游标类型是: dynamic
在定义此类游标的情况下, s锁是必须下的, nolock提示并不会起作用,此现象通过查询游标open时的sp_lock信息就可以观察得到。它产生了is和s锁。
而nolock 提示是否起作用, 会影响的执行的结果(执行计划一样, 但在取数据的时候, 却会有所差异)
对于下面这句, 有nolock 和无nolock 时, 它取的数据是不一样的, 因为它只取了top 100, 而且没有order by 来保证取数的顺序, 所以取数据顺序的细致差异, 就导致了最终结果的不同. 而最终结果的不同, 导致了整个游标取出来的数据不同。
select top(100)
keyid
from tbmaster with(nolock)
where date >= '01/01/2007'
and date < '02/01/2007')
在游标定义select 语句中, 当nolock 有效时, 是可以取到数据的, 但nolock 无效(dynamic 游标导致)时, 查询结果是无数据的
所以最终看到的结果是: 游标循环不出来数据, 但只做查询却有数据。
如果把游标定义中的查询语句的nolock 去掉做查询, 也会没有数据(与dynamic 游标结果一致)
故这个问题严格来说不应该是兼容级别的问题, 在80 级别下, 还是有可能发生, 只是机率更小, 或者是内部执行原理不太一样, 导致没有这种情况出来而已
由于没有order by来保证顺序, 而有无nolock的数据可能不会一样, 所以80与90下都可能出现问题, 只是90会显得比较突出, 或者仅仅时正好被发现了。
解决方法如下:
首先,需要把游标定义改成下面的,这样不会导致nolock 失效, 而且速度比原来的定义方式快得多. 如果游标一定要与原始表的数据变化关联起来, 建议用keyset, 或者是去掉nolock 提示(因为没有意义), 假如对取的数据有要求, 我们还应当考虑加order by来保证取数顺序:
declare mycursor cursor local forward_only read_only static
for
|