【问题标题】:Need some help understanding IO Statistics需要一些帮助来理解 IO 统计信息
【发布时间】:2010-01-06 22:17:41
【问题描述】:

我有一个查询,在执行计划中有一个非常昂贵的 INDEX SEEK 操作。为了追查原因,我设置了 IO STATISTICS 并运行它。在问题部分,它给出了以下统计数据:

表 '#TempStudents_Enrollment2_________________________________________________________________000000004D5F'。扫描计数 0,逻辑读取 60, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表“工作台”。扫描计数 0, 逻辑读取 0,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表 '#TempRace2__________________________________________________________________________________000000004D58'。扫描计数 1,逻辑读取 1, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表“工作台”。扫描计数 0, 逻辑读取 0,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表'RefRace'。扫描计数 120, 逻辑读取 240,物理读取 1, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表“RefFedEnctyRaceCatg”。扫描 计数 18,逻辑读取 36,物理 读取 2,预读读取 0,lob 逻辑读取 0,lob 物理读取 0, lob 预读为 0。

表“#43B0BA0F”。扫描计数 1, 逻辑读取 60,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表“#42BC95D6”。扫描计数 1, 逻辑读取 60,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表“#41C8719D”。扫描计数 1, 逻辑读取 60,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表“#40D44D64”。扫描计数 1, 逻辑读取 60,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表 '#LEA2___________________________________________________________________________________000000004D56'。扫描计数 1,逻辑读取 60, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表“#39332B9C”。扫描计数 1, 逻辑读取 60,物理读取 0, read-ahead 读取 0,lob 逻辑读取 0, lob 物理读取 0, lob 预读为 0。

表 '#School2__________________________________________________________________________________000000004D57'。扫描计数 1,逻辑读取 29164, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表 '#GenderKey________________________________________________________________________________000000004D5A'。扫描计数 1,逻辑读取 29164, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表 '#LangAcqKey_______________________________________________________________________________000000004D5B'。扫描计数 1,逻辑读取 29164, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表 '#TransferCatKey_________________________________________________________________________000000004D5C'。扫描计数 1,逻辑读取 29164, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表 '#ResCatKey________________________________________________________________________________000000004D5D'。扫描计数 1,逻辑读取 29164, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表 'RPT_SnapShot_1_4_StuPgm_Denorm'。扫描 计数 2344954,逻辑读取 4992518, 物理读取 16,预读读取 8, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

表“#3FE0292B”。扫描计数 1, 逻辑读取 2344954,物理读取 0,预读读取 0,lob 逻辑 读取 0,lob 物理读取 0,lob 预读为 0。

表 'RPT_SnapShot_1_4_StuEnrlmt_Denorm'。 扫描计数 20,逻辑读取 87679, 物理读取 0,预读读取 87425,lob 逻辑读取 0,lob 物理读取 0,lob 预读 0.

表 '#GradeKey_________________________________________________________________________________000000004D59'。扫描计数 1,逻辑读取 1, 物理读取 0,预读读取 0, lob 逻辑读取 0,lob 物理 读取 0,lob 预读读取 0。

当我想提高性能时,我应该在这里寻找什么?扫描计数超过 200 万的那条线在我看来很可疑,但我真的不知道。有没有人在这里看到任何我应该更详细地研究的东西?

【问题讨论】:

  • 显示表结构和示例数据以及实际查询会很有用。

标签: sql sql-server sql-server-2005


【解决方案1】:

来源:MS SQL Server 2008 R2 Unleashed

扫描计数 扫描计数值表示对应表被访问的次数 在查询执行期间。嵌套循环连接的外部表通常具有扫描计数 1.内表的扫描计数通常反映内表的次数 table 被搜索,通常与outer中符合条件的行数相同 桌子。内表的逻辑读取次数等于扫描计数的乘积 每次扫描每次查找的页数。请注意,内部的扫描计数 如果 SQL Server 复制所需的行,对于嵌套连接,表有时可能只有 1 从内部表到缓存内存中的工作表,并从工作表中读取 后续迭代(例如,如果它使用 Table Spool 操作)。扫描计数 对于连接中涉及的两个表,散列连接和合并连接通常为 1,但 这些类型的连接的逻辑读取通常要高得多。

逻辑读取 逻辑读取值表示处理所需的页面访问总数 查询。每个页面都是从高速缓存中读取的,即使它首先必须从磁盘中读取。 每一个物理读总是有一个对应的逻辑读,所以物理读的个数 读取永远不会超过逻辑读取的数量。因为同一个页面可能会被多次访问,所以一个表的逻辑读取次数可能会超过总数 表中的页数。

物理读取 物理读取值表示从磁盘读取的实际页数。价值 对于物理读取可能会有很大差异,并且应该减少或降至零,随后 查询的执行,因为数据将由第一个加载到数据缓存中 执行。物理读取的数量也将被带入的页面降低 通过预读机制实现内存。

预读 预读值表示使用读入高速缓存存储器的页数 处理查询时的预读机制。预读器读取的页面 机制不一定会被查询使用。当一页被预读器读取时 机制被查询访问,它算作逻辑读,而不是物理读预读机制可以认为是物理I/O的一种乐观形式, 将页面读入它期望查询在查询之前需要的缓存内存 需要他们。扫描表或索引时,表的索引分配映射 查看页面 (IAM) 以确定哪些范围属于该对象。一个程度 由八个数据页组成。扩展区中的八页是通过单次读取来读取的,并且 这些范围是按照它们存储在磁盘上的顺序读取的。如果桌子分布在 多个文件,预读机制尝试同时从多达 8 个文件中并行读取 时间而不是从 files.read 中顺序读取。

【讨论】:

    【解决方案2】:

    那里似乎有一个相当昂贵的索引scanTable 'RPT_SnapShot_1_4_StuPgm_Denorm'. Scan count 2344954, logical reads 4992518

    【讨论】:

    • 我也是这么想的。据我所知,执行计划中的这一部分作为索引查找返回,需要很长时间。这些有关系吗?
    • 它可能是内部循环连接中的索引搜索,所以如果你可以将它更改为哈希匹配连接(或者更好 - 合并连接),那么它可能会更快。跨度>
    • 我认为您可能是对的,我的执行计划显示 27% 的费用用于在我的 Index Seek 操作之前的嵌套循环(占 70%)。我如何将其更改为哈希匹配或合并连接?更好的索引?
    • 在进行一些调查时,我发现以下引用:“最快的 JOIN 方法是 Loop JOIN,其次是 Merge 和 Hash JOIN。”这是真的?如果是这样,是否有一些特殊情况我想使用其他东西?
    • 合并连接总共只需要两次索引扫描/搜索,而不是每个外部行的索引搜索。更好的索引可能会有所帮助,并且还可以重组查询 - 例如使用连接到组而不是子查询。
    【解决方案3】:

    您已经执行了“set statistics IO on”。在“查询”菜单中打开“包括实际执行计划”和“包括客户统计”。 运行您的查询/程序。 在“messages”标签中查找最高的“Logical reads”数字,记住该表。 在“执行计划”选项卡中,查找您在之前的步骤中找到的表(通常在计划中具有最高的成本百分比)。 如果是“Scan”(表扫描或索引扫描),则您缺少适当的索引,或者适当的索引没有良好的统计信息。 如果它是“Seek”,那么您正在寻找的行是广泛分散在块中的。您必须通过在您寻找的列上创建 CLUSTERED 索引来将它们物理结合在一起。这是非常有效的方法。 没有多少人知道聚集索引是什么。花一些时间研究它们。默认情况下,Sql server 创建集群的主键,大多数人都是这样。在许多情况下,它会导致性能下降。您需要聚集索引按您构建聚集索引的列将行物理分组在一起。每个表只能有一个聚集索引。聚集索引不必是唯一的,不必是 PK,可以包含多个列。 您可以重写查询,例如用 IN 替换存在,反之亦然,或者用表连接替换存在。 没有“最快”的加入方法。如果有一个,所有其他类型将自动转换为最快的一种。这取决于数据、可用索引、内存量等。

    始终衡量,不要假设。测量只是真理。对于您设法减少了多少逻辑读取,您成功地优化了查询。其他优化将是由 DBA 完成的数据库范围级别(内存缓存、并行进程、存储系统、检查等待事件等)。

    【讨论】:

      【解决方案4】:

      唯一值得担心的数字是“逻辑读取”。物理读取将取决于当前缓存的数据量,每次运行查询时都会发生变化。

      扫描计数有时能说明问题,但并不真正值得关注。

      编辑:查看更多关于这些结果的讨论in this post here. 我所说的“告诉”的意思是,扫描计数有时可能是一个“标志”,表明 SQL 从该表中检索数据效率低下。但是,当您在优化时尝试不同版本的查询时,我更加关注我可以在逻辑读取中做出的改进。

      【讨论】:

      • 有趣,您能否详细说明一下您所说的“扫描计数有时会告诉...”是什么意思?
      猜你喜欢
      • 2018-09-06
      • 2012-02-17
      • 2012-02-10
      • 2012-02-02
      • 2016-02-10
      • 1970-01-01
      • 2022-09-24
      • 2023-03-28
      • 2012-03-24
      相关资源
      最近更新 更多