基本概念:
数据页:一个新表被创建之时,系统将在磁盘中分配一段以8K为单位的连续空间,当字段的值从内存写入磁盘时,就在这一既定空间随机保存,当一个 8K用完的时候,数据库指针会自动分配一个8K的空间。这里,每个8K空间被称为一个数据页(Page)。
扩展区:每个数据页分配从0-7的页号, 每个文件的第0页记录引导信息,叫文件头,每8个数据页(64K)的组合形成扩展区(Extent)
什么是页分裂?
当我们新建索引后,数据的变动会导致索引混乱,使得一部分数据在老页面,一部分在新的页面,并且新页面可能被分配到任何可用的页。比如,我们在120页上有1月和2月的数据,在121页上有3月数据,现在,我插入了一些1月和2月的数据,但是120页上存不下了,于是存到新页面页号129,当我们查询数据时,会先查120页然后跳到129页,再跳到121页,这样的操作多了,数据库查询也就卡了,这就是页分裂。所以,频繁页分裂,后果很严重,将使物理表产生大量数据碎片,导致直接造成I/O效率的急剧下降。
如何查看页分裂状况?
首先找到要查找的索引名称:exec sp_helpindex 表名 --查看表中已存在的索引
然后根据使用命令:DBCC showcontig(表名, 索引名称) --查看数据页分裂情况
我们来看查询结果:
扫描页数:就是我们数据表中存储数据用了多少数据页
扫描区数:就是储存页用了多少个区,8页为一个区
每个区的平均页数:7.9,这个是每个区平均有多少页数据
扫描密度:如果所有的页都是连着的就是100%,数值越小跳转越频繁,我这里12.63%。。。
逻辑扫描碎片:页分裂导致的碎片已达到99.28%,几乎全是碎片
区扫描碎片:99.72%,区之间跳转也不是连续的
解决方法:
整理碎片:DBCC indexdefrag(数据库名称, 表名, 索引名称) --碎片整理
其次,可以填充填充因子来减少页分裂,比如我们设置填充因子为45,那么页里就会有55%的空间余出来,再插入数据时就会放到这55%中,即减少了页分裂。
注意:填充因子为0或100时,在所有方面都是相同的
修改填充因子相关语句:
--在某个索引上重新创建填充因子
CREATE NONCLUSTERED INDEX 索引名称 ON 表名(字段名称)
with drop_existing,fillfactor=90
--修改已存在的索引的填充因子值
ALTER INDEX 索引名称 ON 表名
REBUILD WITH (FILLFACTOR = 100);
--查看所有索引的扩充因子
SELECT OBJECT_NAME(object_id) AS TableName ,
name AS IndexName ,
type_desc ,
fill_factor
FROM sys.indexes
WHERE type_desc <> ‘HEAP‘
--查看数据库扩充因子默认值
SELECT [Description] ,
value_in_use
FROM sys.configurations
WHERE name = ‘fill factor (%)‘