简介

    最近在一个客户那里注意到一个计数器很高(Forwarded Records/Sec),伴随着间歇性的磁盘等待队列的波动。本篇文章分享什么是forwarded record,并从原理上谈一谈为什么Forwarded record会造成额外的IO。

 

存放原理

    在SQL Server中,当数据是以堆的形式存放时,数据是无序的,所有非聚集索引的指针存放指向物理地址的RID。当数据行中的变长列增长使得原有页无法容纳下数据行时,数据将会移动到新的页中,并在原位置留下一个指向新页的指针,这么做的原因是由于使得当出现对Record的更新时,所有非聚集索引的指针不用变动。如图1所示。

图1.Forwarded Record示意

 

    这种由于数据更新,只在原有位置留下指针指向新数据页存放位置行,就是所谓的Forwarded Record。

 

Forwarded Record如何影响IO性能?

    那么Forwarded Record既然是为了提升性能存在的机制,为什么又会引起性能问题?Forwarded Record的初衷是为了对堆表进行更新时,堆表上存储位置的变化不会同时更新非聚集索引而产生开销。但对于查找来说,无论是堆表上存在表扫描,还是用于书签查找,都会成倍带来额外的IO开销,下面看一个例子。

CREATE TABLE dbo.HeapTest ( id INT, col1 VARCHAR(800) )

DECLARE @index INT
SET @index = 0
BEGIN TRAN
WHILE @index < 100000
BEGIN
INSERT INTO dbo.HeapTest
( id, col1 )
VALUES ( @index, NULL )
SET @index = @index + 1 END
COMMIT

代码清单1.新建堆表并插入10万条数据

 

 

    通过代码清单1创建测试表,并循环插入10万数据。此时我们来看该堆表所占用存储的页数,如图2所示。

图2.堆表空间占用

 

    此时对该表进行更新,让原有行增长,产生Forwarded Record,此时再来看该堆表的存储。如图3所示。

图3.产生8W+的forwarded record

 

    此时我们注意到,虽然数据仅仅占到590页,但存在8W+的forwarded record,如果我们对该表进行扫描,则会看到虽然仅仅只有590页,但需要8W+的逻辑IO,大大提升了对IO的开销压力,此外由于forwarded record页与原页往往不物理连续,因此对IOPS也存在挑战。如图4所示。

图4.不该产生的额外IO开销

 

    而上面查询反映到性能计数器中,则呈现为如图5所示的结果。

图5.Forwarded Record计数器增长

 

如何解决

    看到Forwarded Record计数器,就说明数据库中存在堆表,在OLTP系统中,所有的表上都应该有聚集索引。因此可以通过在表上增加聚集索引来解决该问题。

    通常来讲,只有只写不读的表设置为堆表比较合适,但如果看到存在Forwarded Reocord,则说明堆表上存在读操作,那么找到该堆表,找一个合适的维护窗口时间创建聚集索引则是比较理想的选择。

    如果由于其他原因无法创建聚集索引,则可以对堆表进行表重建。

SQL Server中一个隐性的IO性能杀手-Forwarded record的更多相关文章

  1. Sql Server 中一个非常强大的日期格式化函数

    Sql Server 中一个非常强大的日期格式化函数Select CONVERT(varchar(100), GETDATE(), 0)-- 05 16 2006 10:57AMSelect CONV ...

  2. SQL Server中使用Check约束提升性能

        在SQL Server中,SQL语句的执行是依赖查询优化器生成的执行计划,而执行计划的好坏直接关乎执行性能.     在查询优化器生成执行计划过程中,需要参考元数据来尽可能生成高效的执行计划, ...

  3. 如何把SQL Server中一个表,一个存储过程,一个视图等改为系统表,系统存储过程,系统视图等

    使用如下存储过程即可: EXEC sys.sp_MS_marksystemobject '[dbo].[TableNameToSystem]' 其中"[dbo].[TableNameToSy ...

  4. SQL Server中数据库文件的存放方式,文件和文件组 (转载)

    简介 在SQL SERVER中,数据库在硬盘上的存储方式和普通文件在Windows中的存储方式没有什么不同,仅仅是几个文件而已.SQL SERVER通过管理逻辑上的文件组的方式来管理文件.理解文件和文 ...

  5. 从TXT文本文档向Sql Server中批量导入数据

    下面我们通过以下的简单的SQL语句即可实现数据的批量导入,代码如下: Bulk insert id From 'G:\文档\test.txt' With ( fieldterminator=',', ...

  6. SQL Server中的日期格式化

    SQL Server中文版的默认的日期字段datetime格式是yyyy-mm-dd Thh:mm:ss.mmm 例如: select getdate()    2004-09-12 11:06:08 ...

  7. SQL Server中怎么查看每个数据库的日志大小,以及怎么确定数据库的日志文件,怎么用语句收缩日志文件

    一,找到每个数据库的日志文件大小 SQL Server:查看SQL日志文件大小命令:dbcc sqlperf(logspace) DBA 日常管理工作中,很重要一项工作就是监视数据库文件大小,及日志文 ...

  8. 如何识别SQL Server中的IO瓶颈

    原文:如何识别SQL Server中的IO瓶颈 原文出自: http://www.mssqltips.com/sqlservertip/2329/how-to-identify-io-bottlene ...

  9. SQL Server中多表连接时驱动顺序对性能的影响

    本文出处:http://www.cnblogs.com/wy123/p/7106861.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

随机推荐

  1. WPF 图片显示中的保留字符问题

    在WPF中显示一张图片,本是一件再简单不过的事情.一张图片,一行XAML代码即可. 但是前段时间遇到了一件奇怪的事: 开发机上运行正常的程序,在某些客户机器上却显示不了图片,而且除了这个问题,其它运行 ...

  2. Android最大可运行内存

    int maxMemory = (int) Runtime.getRuntime().maxMemory();

  3. Ajax&json

    通过json-lib方式 复杂情况:

  4. wpf 报错: 在 AddNew 或 EditItem 事务过程中不允许“DeferRefresh”。

    今天修改Bug的时候遇到一个问题: datagrid 设置了双击事件,双击弹出一个窗口,在多次点击后报错:在 AddNew 或 EditItem 事务过程中不允许“DeferRefresh” 网上查了 ...

  5. Android editview 设置只能输入数字、字母和汉字

    Android editview 设置只能输入数字.字母和汉字 当处理密码.昵称等特殊情况的时候,往往需要对输入内容加以限制.对于单纯的一种输入法限制可以对键盘和editview熟悉进行控制,而对于多 ...

  6. erlang日志功能。

    用cowboy这个库,没有日志功能,所以研究了otp提供的日志功能. 1.启动SASL的方式 erl –boot start_sasl 默认配置文件下启动SASL, {env, [{sasl_erro ...

  7. HTML5-列表的使用

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  8. Java 程序性能优化

    1. singleton延时初始化 class Singleton { private static Singleton _instance = null; public synchronized S ...

  9. ORACLE10g数据库字符集设置和客户端字符集设置不一致问题

    在家里自己电脑上又重新安装了Oracle 10g和PLSQL Developer,装完后启动PLSQL Developer,弹出如下错误信息: 解决方案: 在Windows运行命令行中输入regedi ...

  10. Redis中Value使用hash类型的效率是普通String的两倍

    什么Redis? 点击这里 最近要开发的一个项目是分布式缓存组件,解决参数缓存高效获取的问题.参数达到了500万级别,刚刚开始了解Redis.做设计的时候考虑到Value使用哪种类型的问题? 主要面临 ...