关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » SQL语言 »游标脚本性能问题详解之游标分类特点篇

    游标脚本性能问题详解之游标分类特点篇

    2011-04-06 09:30:00 出处:ITJS
    分享

    从上篇游标脚本性能问题详解之案例实践篇两个脚本执行情况的对比中可以看出,游标的选择对语句执行的性能具有一定的影响。

    在SQL Server联机丛书上列出了不止十种游标类型,但是所有游标都可以被划到两大类别:

    1. 通过从首次得到结果的临时拷贝映像静态进行

    2. 每次fetch都通过动态进行且真正查阅表

    STATIC、KEYSET、READ_ONLY和FAST_FORWARD属于第一大类,FORWARD_ONLY、DYNAMIC和OPTIMISTIC属于第二大类。

    下面我们来进行一定的比较分析,并学习如何使用各种游标。在进行这部分之前,大家要引入另一个set statistics的方法: set statistics profile on

    这个option会帮助我们打印出文本格式的执行计划和每一布的执行统计信息。这个部分的执行语句执行计划都是通过这个option打印的。

    1. 首先,我们把游标脚本中的SQL语句抽取出来直接运行而不使用游标:

    SELECT       T1.*  FROM         dbo.S_AUDIT_ITEM T1              LEFT OUTER JOIN dbo.S_USER T2   ON T1.USER_ID = T2.PAR_ROW_ID      WHERE   T1.BC_BASE_TBL = 'S_PARTY' AND   T1.RECORD_ID = '1-10350J' ORDER BY       T1.OPERATION_DT DESC  

    执行情况如下:逻辑读15次,使用的是索引查找(index seek)

    Table 'S_USER'. Scan count 1, logical reads 260, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.  Table 'S_AUDIT_ITEM'. Scan count 1, logical reads 15, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.  

    执行计划为:

    Rows                 Executes             StmtText                                                                                                   -------------------- -------------------- ---------------------------------------------------------------------------------------------------------  4                    1                    SELECT  T1.*  FROM  dbo.S_AUDIT_ITEM T1                                                                                                                     LEFT OUTER JOIN dbo.S_USER T2                                                                                                                        ON T1.USER_ID = T2.PAR_ROW_ID                                                                                                                        WHERE   T1.BC_BASE_TBL = 'S_PARTY' AND   T1.RECORD_ID = '1-10350J'                                                                                 ORDER BY  T1.OPERATION_DT DESC            1    1    0      NULL         NULL                     4                    1                      |--Sort(ORDER BY:([T1].[OPERATION_DT] DESC))                                                             4                    1                           |--Nested Loops(Left Outer Join, WHERE:([testcursor].[dbo].[S_AUDIT_ITEM].[USER_ID] as [T1].[USER_  4                    1                                |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1002], [T1].[ROW_ID]) OPTIMIZED)            4                    1                                |  |--Index Seek(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_M3] AS [T1]), SEEK  4                    4                                |  |--Clustered Index Seek(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_P1] AS [  66908                4                                |--Table Scan(OBJECT:([testcursor].[dbo].[S_USER] AS [T2]))     

    2. 下面通过T-SQL语句打开一个游标。注意,这里创建的游标为dynamic类型,因为新声明的游标默认类型为dynamic。。本文开头使用的存储过程是调用API游标的写法,这里是用T-SQL语句打开游标,两种写法使用的游标类型和执行的语句是完全一样的。

    declare @CONFLICT_ID int declare curTest cursor  FOR     SELECT          T1.CONFLICT_ID      FROM         dbo.S_AUDIT_ITEM T1                  LEFT OUTER JOIN dbo.S_USER T2      ON T1.USER_ID = T2.PAR_ROW_ID          WHERE      T1.BC_BASE_TBL = 'S_PARTY' AND   T1.RECORD_ID ='1-10350J'         ORDER BY       T1.OPERATION_DT     OPEN curTest  FETCH NEXT FROM curTest   INTO @CONFLICT_ID  CLOSE curTest   deallocate curTest 

    执行情况为:逻辑读明显增多,使用索引扫描(index scan)

    Table 'Worktable'. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.                 Table 'S_USER'. Scan count 1, logical reads 64, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.                   Table 'S_AUDIT_ITEM'. Scan count 1, logical reads 3026834, physical reads 1292, read-ahead reads 5574, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.  

    执行计划如下:

    Rows                 Executes             StmtText                                                                                                                          -------------------- -------------------- --------------------------------------------------------------------------------------------------------------------------------  1                    1                    FETCH NEXT FROM curTest                                                                                                           INTO @CONFLICT_ID                                                                                                                                                           1                    1                      |--Clustered Index Insert(OBJECT:(CWT), SET:([CWT].[COLUMN0] = [testcursor].[dbo].[S_AUDIT_ITEM].[ROW_ID] as   1                    1                           |--Compute Scalar(DEFINE:([Expr1008]=CWT_ROWID()))                                                                         1                1                                |--Nested Loops(Left Outer Join, WHERE:([testcursor].[dbo].[S_AUDIT_ITEM].[USER_ID] as   1                    1                                     |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1004], [T1].[ROW_ID]))                                        1007751              1                                     |    |--Index Scan(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_M4] AS     1                    1007751                               |    |--Clustered Index Seek(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_P1] AS   16401                1                                     |--Table Scan(OBJECT:([testcursor].[dbo].[S_USER] AS [T2]))  

    接下来,我们使用其他类型的游标进行测试,从它们的测试结果会发现:

    当使用STATIC、KEYSET、READ_ONLY、FAST_FORWARD类型的游标,可以得到理想的执行计划(索引S_AUDIT_ITEM_M3上使用索引查找)。

    但是,假如使用其他第二类游标类型,得到的执行计划就不甚理想了(索引S_AUDIT_ITEM_M4上使用索引扫描)。

    从上面的测试,我们知道STATIC、KEYSET、READ_ONLY及FAST_FORWARD游标可以带给我们同样的理想结果。那么,这些游标有什么共同点

    我们可以分析一下两大游标类型执行计划的不同:

    1. STATIC、KEYSET、READ_ONLY、FAST_FORWARD类型游标的执行计划:

    Executes             StmtText                                                                                                              -------------------- --------------------------------------------------------------------------------------------------------------------  1                    OPEN curTest                                                                                                          1                      |--Clustered Index Insert(OBJECT:(CWT), SET:([CWT].[COLUMN0] = [testcursor].[dbo].[S_AUDIT_ITEM].[CONFLICT_ID] as   1                           |--Sequence Project(DEFINE:([Expr1008]=i4_row_number))                                                         1                                |--Segment                                                                                                1                                     |--Sort(ORDER BY:([T1].[OPERATION_DT] ASC))                                                          1                                          |--Nested Loops(Left Outer Join, WHERE:([testcursor].[dbo].[S_AUDIT_ITEM].[USER_ID] as [T1].[U  1                                               |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1004], [T1].[ROW_ID]) OPTIMIZED)        1                                               |    |--Index Seek(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_M3] AS [T1]),   4                                               |    |--Clustered Index Seek(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_P1]   4                                               |--Table Scan(OBJECT:([testcursor].[dbo].[S_USER] AS [T2]))                                                                                                                                      Executes             StmtText                                                                                        StmtId      NodeId    -------------------- ----------------------------------------------------------------------------------------------- ----------- --------  1                    FETCH NEXT FROM curTest INTO @CONFLICT_ID                       2           1           1                      |--Clustered Index Seek(OBJECT:(CWT), SEEK:([CWT].[ROWID]=FETCH_RANGE((0))) ORDERED FORWARD)  2           2         

    2. dynamic类型游标的执行计划

    Executes   StmtText                                                                                                                      ---------------------------------------------------------------------------------------------------------------------------------------  1          FETCH NEXT FROM curTest                                                                                                                                                                                                                                                1            |--Clustered Index Insert(OBJECT:(CWT), SET:([CWT].[COLUMN0] = [testcursor].[dbo].[S_AUDIT_ITEM].[ROW_ID] as [T1].[ROW_ID]  1                 |--Compute Scalar(DEFINE:([Expr1008]=CWT_ROWID()))                                                                     1                      |--Nested Loops(Left Outer Join, WHERE:([testcursor].[dbo].[S_AUDIT_ITEM].[USER_ID] as [T1].[USER_ID]=[testcurso  1                           |--Nested Loops(Inner Join, OUTER REFERENCES:([Uniq1004], [T1].[ROW_ID]))                                    1                           |    |--Index Scan(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_M4] AS [T1]), ORDERED BACKWARD)   1007751                     |    |--Clustered Index Seek(OBJECT:([testcursor].[dbo].[S_AUDIT_ITEM].[S_AUDIT_ITEM_P1] AS [T1]), SEEK:([T  1                           |--Table Scan(OBJECT:([testcursor].[dbo].[S_USER] AS [T2]))  

    比较一下两个执行计划的FETCH NEXT部分(SQL Server在游标打开阶段不会读取表):在第一个执行计划中,FETCH是直接从临时对象CWT中得到行,然后从CWT.ROWID中找到相应范围。而在第二个计划中,FETCH是动态的而且是真正对表进行了读取,从表中取得数据。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    SQL汉字转换为拼音的函数

    windows 7系统无法运行Photoshop CS3的解决方法

    巧用MySQL加密函数对Web网站敏感数据进行保护

    MySQL基础知识简介

    Windows7和WinXP下如何实现不输密码自动登录系统的设置方法介绍

    windows 7系统ip地址冲突怎么办?windows 7系统IP地址冲突问题的

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。