关闭 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是动态的而且是真正对表进行了读取,从表中取得数据。

    上一篇返回首页 下一篇

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

    别人在看

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    小米路由器买哪款?Miwifi热门路由器型号对比分析

    IT头条

    Synology 对 Office 套件进行重大 AI 更新,增强私有云的生产力和安全性

    01:43

    StorONE 的高效平台将 Storage Guardian 数据中心占用空间减少 80%

    11:03

    年赚千亿的印度能源巨头Nayara 云服务瘫痪,被微软卡了一下脖子

    12:54

    国产6nm GPU新突破!砺算科技官宣:自研TrueGPU架构7月26日发布

    01:57

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

    02:03

    技术热点

    最全面的前端开发指南

    Windows7任务栏桌面下角的一些正在运行的图标不见了

    sql server快速删除记录方法

    SQL Server 7移动数据的6种方法

    SQL Server 2008的新压缩特性

    每个Java程序员必须知道的5个JVM命令行标志

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

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