表现:
将数据库兼容级别从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 信息可以观察得到.它产生了ISS
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
 
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐