• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
鱼要的是海洋,鸟要的是天空,我要的是自由!
平凡的人不平凡的人生
博客园    首页    新随笔    联系   管理    订阅  订阅

游标类型产生的数据检索问题

表现:

将数据库兼容级别从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

posted @ 2007-06-29 14:44  伊凡  阅读(252)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3