SQL Server 存储引擎-剖析Forwarded Records

原文:SQL Server 存储引擎-剖析Forwarded Records

我们都知道数据在存储引擎中是以页的形式组织的,但数据页在不同的组织形式中其中对应的数据行存储是不尽相同的,这里通过实例为大家介绍下堆表的中特有的一种情形Forwared Records及处理方式.

概念

堆表中,当对其中的记录进行更新时,如果当前数据页无法满足更新行的容量,此时这行记录将会转移到新的数据页中,而原数据页中将会留下指针(文件号,页号,槽号)链接到新的数据页中.

Code 创建测试数据

create database testpage
go
use testpage
go
create table testtb
(
id int identity(1,1),
str1 char(100) default replicate('a',100),
str2 varchar(2000) default replicate('b',500),
str3 varchar(2000) default replicate('c',1000)
)
go

insert into testtb default values
go 20

Code 查看相关数据页 如图1-1

DBCC TRACEON(3604)

GO

DBCC IND(testpage,'testtb', 1)---find the data page

GO

DBCC PAGE('testpage', 1, 79, 3)-----view data page find slot 2(ID=3)

GO

                                  

                                                              图1-1

现在我们来更新ID=3的数据使当前数据页(79)无法容纳此行数据,然后观察数据页,

Code

update dbo.testtb set str2=replicate('t', 1000) where ID=3--update ID=3

GO

DBCC PAGE('testpage', 1, 79, 3)

GO

继续找到slot 2槽位(ID=3)观察 如图1-2所示,此时slot2数据的Record Type = FORWARDING_STUB,也就是此时槽位2只留下RID记录,数据转到其他数据页中了(Forwarding to  =  file 1 page 94 slot 0  )

 

                                                图1-2

 

这里稍微深入的讲下RID的存储内容,实例中根据dbcc page已经给我们展示RID的内容,实际上存储是16进制的如图1-2中的黑色部分(045e0000 00010000 00

).具体对应RID内容如图1-3

                                            图1-3

 

我们在找到实际存储ID=3的数据页看下数据内容(1:94:0) 如图1-4

图中我省去了数据内容

code

DBCC PAGE('testpage', 1, 94, 3)

GO

                                         图1-4

 

接下来我们继续更新ID=3让新的数据页也无法容纳它,然后观察相应的数据页如图1-5(三个dbcc page 合成图)

(此时ID=3的原始页94,槽号2指向了新的数据页位置184)如图所示1-5所示

code

insert into testtb default values
go 20----先插入一些数据

update dbo. Testtb set str2=replicate('t', 2000),str3=replicate('t', 2000) where ID=3 GO---继续更新ID=3

DBCC PAGE('testpage', 1, 79, 3)--------源ID=3,现在执行(1:184:2)
GO
DBCC PAGE('testpage', 1, 94, 3)--------第一次修改时ID=3存储位置(1:94:0),现在slot 0没有了
GO
DBCC PAGE('testpage', 1, 184, 3)------目前id=3的数据存储位置
GO

 

                                               图1-5

 

可以看出id=3的原始页(1:79:2)的数据再次变更后的由(1:94:0)挪到了(1:184:2)中,

而页号94槽号0就不存在了.

堆表中的非聚集索引.

当堆表中有非聚集索引存在时,非聚集索引RID指向的原始页位置

我们通过实例看下

注:关于heap rid我就不做详细介绍了,实例中通过查询转换可以算出10进制对应的RID

Code

CREATE UNIQUE NONCLUSTERED INDEX inx_1 ON testtb (id )

DBCC IND(testpage,'testtb', -1)----find the index page (page type 2)115
GO
DBCC PAGE('testpage', 1, 115, 3)---find the heap rid where id=3 heap rid =0x4F00000001000200

DECLARE @HeapRid BINARY(8)
SET @HeapRid = 0x4F00000001000200
       SELECT
       CONVERT (VARCHAR(5),
                    CONVERT(INT, SUBSTRING(@HeapRid, 6, 1)
                               + SUBSTRING(@HeapRid, 5, 1)))
     + ':'
     + CONVERT(VARCHAR(10),
                    CONVERT(INT, SUBSTRING(@HeapRid, 4, 1)
                               + SUBSTRING(@HeapRid, 3, 1)
                               + SUBSTRING(@HeapRid, 2, 1)
                               + SUBSTRING(@HeapRid, 1, 1)))
     + ':'
          + CONVERT(VARCHAR(5),
                    CONVERT(INT, SUBSTRING(@HeapRid, 8, 1)
                               + SUBSTRING(@HeapRid, 7, 1)))
                               AS 'Fileid:Pageid:slot'

可以看到select 的输出正好是(1:79:2)我们原始的id=3的位置

 

关于性能

由于forwarded record的存在,当访问到这种数据行时,会消耗额外的随机IO,从而影响性能.更有甚者,由于额外的数据页被放入内存中,造成BP的污染,致使性能下降.

(研发要求对一个频繁访问的大堆表更新扩充栏位,执行完了性能依旧下降有木有?)

 

我们通过简单实例来看下

访问forwarded record会造成额外IO如图2-1

Code

set statistics io on

select * from testtb where id=2

select * from testtb where id=3

                                    图2-1

当表数据量大时,大批量更新扩充栏位会造成对缓冲池的污染

code

create table testbp
(
id int identity(1,1),
str1 char(100) default replicate('a',100),
str2 varchar(2000) default replicate('b',500),
str3 varchar(2000) default replicate('c',1000)
)
go
insert into testbp default values
go 10000

dbcc dropcleanbuffers
select * from testbp

SELECT count(*)*8/1024 AS 'Cached Size (MB)'
,CASE database_id
WHEN 32767 THEN 'ResourceDb'
ELSE db_name(database_id)
END AS 'Database'
FROM sys.dm_os_buffer_descriptors with(nolock)
where db_name(database_id)='testpage'
GROUP BY db_name(database_id) ,database_id
-----buffer pool 15MB

update dbo. testbp set str2=replicate('t', 1000)---make forwarded recordes

dbcc dropcleanbuffers

select * from testbp

SELECT count(*)*8/1024 AS 'Cached Size (MB)'
,CASE database_id
WHEN 32767 THEN 'ResourceDb'
ELSE db_name(database_id)
END AS 'Database'
FROM sys.dm_os_buffer_descriptors with(nolock)
where db_name(database_id)='testpage'
GROUP BY db_name(database_id) ,database_id
------31MB

顺序执行代码时可以看出,testpage表更改前后占Buffer Pool的大小分别为15M,31M,对BP影响明显.

监控/发现

实际生产环境中我们需要监控一些性能指标用来辅助DBA解决问题,保证运维效率,针对这里,我们监控性能计数器中SQL Server Access Methods对象中的forwarded records/sec,如果你设定的了性能Baseline,这个值如果有异常变化,则需要我们关注.

同时我们也可以根据系统的DMF找出特定对象的forwarded records信息.代码如下

select
    object_name(object_id) as objectName
    ,index_type_desc
    ,forwarded_record_count
 from
    sys.dm_db_index_physical_stats(db_id(),null,null,null, 'detailed')
    where object_name(object_id)='testbp'
------view the forwarded records info

注:可以通过简单的Batch检索整个库甚至实例中的堆表的相关信息,有兴趣的朋友自己写下.

处理

如果发现了因为forwarded Recordes引起的性能问题,我们可以选择表中创建聚集索引改变数据组织结构(forwarded Recordes只在堆表中存在).如果无法添加聚集索引,也可以选择重组堆表(alter table heap rebuild)操作时应注意时间窗口

结语

任何事物都存在因果,套用数据库系统中,我们应该清楚自己的所作所为,以及带来的效用/影响.合理到位的分析,评估会让我们的工作变得从容.

时间: 2024-09-21 09:23:20

SQL Server 存储引擎-剖析Forwarded Records的相关文章

SQL Server存储引擎容量的规划技巧

概述 巧妙的规划是实现关系型数据库管理系统(RDBMS)的基础.要满足对更多存储容量的要求,对更快地取得信息的要求,它是唯一方法.想从Microsoft SQL Server 7.0中获得最多,要求组织机构了解它的关键部件--存储引擎--内在和外在.本文是存储引擎结构的高级指南,推荐了配置参数,SQL Server的最佳硬件,以及通过文件和文件组存储大量数据的创新方法.本文也概述了SQL Server 7.0存储引擎的新的动态特性,它使雇员花最少的努力公司数据库应用程序. 介绍 十年前,数据库应

SQL Server 2008引擎组件

首先让我们先来看看SQL Server2008的引擎组件,SQLServer2008有四大组件:协议.关系引擎.存储引擎和SQLOS. 协议层(Protocol Layer) 当一个应用程序与SQL Server数据库引擎通讯时,协议层提供的应用程序编程接口利用微软自定义的tabular data stream(TDS)package来规范通讯格式.这一层的意义在于向应用程序提供访问SQL Server的接口. SQL Server Network Interface(简称SNI) SNI是在服

使用 Osql 工具管理 SQL Server 桌面引擎 (MSDE 2000)应用介绍_数据库相关

概要 "SQL Server 桌面引擎"(也叫 MSDE 2000)没有自己的用户界面,因为它主要设计为在后台运行.用户通过 MSDE 2000 嵌入的程序与它交互. MSDE 2000 提供的唯一工具是 Osql .可执行文件 Sql.exe 在 MSDE 2000 的默认实例的 MSSQL/Binn 文件夹中. 本文重点讨论如何通过使用 Osql 工具管理 MSDE 2000. 何为 Osql? Osql 工具是一个 Microsoft Windows 32 命令提示符工具,您可以

一个字节造成的巨大性能差异——SQL Server存储结构

今天同事问了我一个SQL的问题,关于SQL Server内部存储结构的,我觉得挺有意思,所以写下这篇博客讨论并归纳了一下.问题是这样的: 首先我们创建两张表,一张表的列长度是4039字节,另一张表的长度是4040字节,他们就只有一个字节的差距,比如以下创建表的SQL: CREATE TABLE tb4039(c1 INT IDENTITY,c2 char(4035) not null)CREATE TABLE tb4040(c1 INT IDENTITY,c2 char(4036) not nu

六步走战略,助您实现SQL Server存储扩展性提升

  打算对SQL Server存储进行优化?以下六项提示将帮助大家充分利用自己的宝贵资源. SQL Server可扩展性是否已经成为系统优先级列表中的顶端选项?您是否正在努力寻找对SQL Server数据库性能加以优化的途径?也许向外扩展并不是最理想的选择,那么大家不妨遵循以下六个步骤,相信能够更为轻松高效地实现业务规模提升: 1)尽量利用现有SQL Server组件 扩展SQL Server是一项繁琐而耗时的工作,涉及多个系统.分区数据库.内存.存储.CPU以及网络适配器.我们不妨先从最大程度

使用 Osql 工具管理 SQL Server 桌面引擎 (MSDE 2000)应用介绍

概要 "SQL Server 桌面引擎"(也叫 MSDE 2000)没有自己的用户界面,因为它主要设计为在后台运行.用户通过 MSDE 2000 嵌入的程序与它交互. MSDE 2000 提供的唯一工具是 Osql .可执行文件 Sql.exe 在 MSDE 2000 的默认实例的 MSSQL/Binn 文件夹中. 本文重点讨论如何通过使用 Osql 工具管理 MSDE 2000. 何为 Osql? Osql 工具是一个 Microsoft Windows 32 命令提示符工具,您可以

SQL Server内核架构剖析

我们做管理软件的,主要核心就在数据存储管理上.所以数据库设计是我们的重中之重.为了让我们 的管理软件能够稳定.可扩展.性能优秀.可跟踪排错.可升级部署.可插件运行,我们往往研发自己的 管理软件开发平台.我们总是希望去学习别人的开发平台(如用友或金蝶或SAP),但我们却总是感叹管 理软件业务处理细节繁多,而数据库管理软件却简单的SELECT.INSERT.DELETE.UPDATE四个命令就搞定 .我们多希望有一天能做出一个架构,也可以这么简单就搞定管理软件.我们往往研究别人的架构,却忘 记了我们

SQL Server存储图像数据的策略与方法

server|策略|数据 目前对于图像数据的管理大都采用表+实体的方法,即图像数据以文件形式存放于指定的计算机目录下,在数据库表中只反映图像数据文件的存储路径.这种管理模式,给数据的维护增加了难度,同时,也给数据的安全带来一定的隐患.因此,要真正做到各类数据在数据库中安全管理,研究和探索直接将图像数据存储在数据库关系表中的方法是非常必要的. 笔者在Visual Basic 6.0开发环境中,采用客户机/服务器的工作方式,针对SQL Server数据库关系表中存储图像数据的问题进行了初步探讨,提出

SQL Server存储图像数据的机制介绍

本文介绍MIS SQL Server对图像数据的存储机制和存取方法.针对VB开发工具,介绍了一种通过ADO Field 对象的GetChunk 方法和AppendChunk 方法来存取MIS SQL Server中的图像数据的方法. 在一个完善的医院信息MIS中,图像数据的存取是必不可少的,比如X光片.CT像片的保存.一方面,这些图像数据在远程诊疗为准确诊断病情提供了重要的依据,另一方面,也为快速查阅病人资料提供了基本条件.图像数据的存取在其它应用系统如GIS中也有广泛的应用. 1.SQL Se