设为首页 加入收藏

TOP

索引修改内幕(二)
2015-11-21 01:40:20 来源: 作者: 【 】 浏览:2
Tags:索引 修改 内幕
6af) --1 (0x1) - 3326 (0xcfe) --0 (0x0) - 96 (0x60)

?

通过偏移阵列,可以看出页拆分后原来的页和新页各有三行。通过观察DBCC PAGE的输出的行内容,可以看到:
?
原来的页(PID:168)保存着聚集索引键值为5,10和15的行,新页(PID:172)保存着20,21和25的行。
?
在新页上,21这行存储在Slot1的位置上。根据Offset的值,21实际的物理位置却是在25之后。
?
21的逻辑位置在25之前,物理位置在25之后。可以看出:行的聚集索引键顺序是由Slot编号表示的,而不是行的物理位置。也就是聚集索引表中,某行的Slot编号小于另一行,则它的聚集索引键值也小于它。这其实是一种优化的设计结果:当页上发生数据修改时,只需要修改页上偏移阵列的值来保证行的顺序,而不需要物理性的移动数据行位置来保证顺序。极大地减少数据修改的开销。所以“索引中行的物理存储顺序总是与它的索引键值的顺序是一样的。”这种说法是不正确的。实际上,只要偏移阵列提供了正确的逻辑顺序,行可以存储页的任意位置。
?
页拆分的代价是很大的。页拆分过程中对旧页、新页和父页的修改操作,都需要完整写入事务日志。最小化业务高峰期发生页拆分的办法,通常有:
?
选择一个更合理的聚集索引键。比如,让新行插入到表的末尾,而不是像GUID那样随机插入。
?
对于更新变长列引起的页拆分,可以通过减少索引的填充因子(Fill Factor),在页上保留多一些可用空间给变长列更新使用。
?
删除数据行
?
删除数据行时,需要同时考虑数据页和索引页的变化。聚集索引表中删除行与非聚集索引叶级中删除行是一样的方式。
?
叶级中删除行
?
当索引叶级的行被删除时会被标记为幻影行(Ghost Record)。行被删除后,行头的一个位(Bit)被修改,行就标记为幻影,但是行还是保留于页上。页头的元数据m_ghostRecCnt表示当前页的幻影行的数量。幻影行的用途有:
?
快速回滚。当行没有被物理删除时,回滚Delete操作只需要修改行头的表示幻影行的位即可。
?
键值范围锁定(key-Range Locking)和其它锁定的并发优化
?
用于行版本控制
?
幻影行什么时候被清除,由系统负载决定。SQL Server有一个叫做ghost-cleanup的后台线程,用于清理那些不再需要被活动事务和其它功能使用的幻影行。幻影行可能很快被ghost-cleanup线程清除掉。所以为了观察幻影行,可以将Delete包裹在未被提交或者回滚的用户事务中,或者使用末公开的(Undocumented)跟踪标记661来禁用幻影行清理功能。可以使用存储过程sp_clean_db_free_space清除整个库的幻影行,也可以用sp_clean_db_fie_free_space清除库中指定数据文件中的全部幻影行。
?
下面的例子,删除聚集索引表中的一行,观察幻影行。
USE test
GO
IF object_id('dbo.smallrows') IS NOT NULL
 DROP TABLE dbo.smallrows;
GO
CREATE TABLE dbo.smallrows
(
 a int IDENTITY PRIMARY KEY,
 b char(10)
);
GO
INSERT INTO dbo.smallrows
 VALUES ('row 1');
INSERT INTO dbo.smallrows
 VALUES ('row 2');
INSERT INTO dbo.smallrows
 VALUES ('row 3');
INSERT INTO dbo.smallrows
 VALUES ('row 4');
INSERT INTO dbo.smallrows
 VALUES ('row 5');
GO
--get data page id
select allocated_page_file_id as PageFID,allocated_page_page_id as PagePID,page_type_desc
from sys.dm_db_database_page_allocations(db_id('test'),object_id('smallrows'),null,null,'Detailed')
go
DELETE FROM dbo.smallrows
WHERE a = 3;
GO
dbcc traceon(3604)
dbcc page(test,1,174,1)
go

?

截取DBCC PAGE输出中与幻影行相关的内容。
?
页头中(Page Header)中的 m_ghostRecCnt = 1,表示当前页中幻影行数量是1。
?
Slot2中的Record Type = GHOST_DATA_RECORD,表示当前行是幻影行。
?
偏移阵列中,Slot2的偏移量没有变,其它Slot的偏移理也没有变化。表示没有行发生移动。
OFFSET TABLE:
Row - Offset
4 (0x4) - 180 (0xb4)
3 (0x3) - 159 (0x9f)
2 (0x2) - 138 (0x8a)
1 (0x1) - 117 (0x75)
0 (0x0) - 96 (0x60) ??
?
可以通过sys.dm_db_index_physical_stats查看表中的幻影行总数。
?
中间级中删除行
?
中间级中删除行与从堆表中删除行类似。中间级页中被删除行,不会被标记为幻影行,所占用的页空间也不会立刻释放,当有新索引行需要页面上的空间时才被释放和重用。
?
页回收
?
数据页上所有行被删除后,这个页会被ghost-cleanup线程回收(Dealocated)。堆表是个例外。如果表只有一个数据页,此页也不会被回收。当数据页被删除,指向这些数据页的索引行会被删除。中间级页上索引行全被删除,不会马上回收,而是会在页上保留一行,这一行稍后会被移动到邻近的有空闲空间的页上,然后回收原来的空页。
?
更新行
?
SQL Server会自动选择最优的数据更新策略。基于受影响行数,访问数据的方式和是否需要修改索引键来选择最优的策略。更新实现方式包括:直接将旧值原地修改为新值;删除旧行再插入新行。
?
行移动
?
发生行移动的两种情况:
?
当行中的变长列被更新后,原来位置无法再存储它时
?
因为行的逻辑顺序由索引键决定,所以当聚集索引或者非聚集索引的键列发生修改后,行的逻辑顺序发生改变时。例如当在lastname列上建立聚集索引,lastname为Abel的行存储在接近表开始的位置,如果将Abel修改为Zek,则将会被移动到接近表结束的位置。
?
非聚集索引的叶级中包含指向表中每一行的行定位器。聚集索引表中,行定位器就是聚集索引键。所以仅当聚集索引键被修改时,非聚集索引才会被修改。因此选择聚集索引键列时,尽量选择非易失性的列(数据修改率极
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇通过亚马逊电影评论的数据包抓取.. 下一篇SQL 中GO的作用

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: