性能優化與故障排除百日談(16)-索引的維護-設置填充因子-誤區解析
我們在之前的文章中已經多次提到了“填充因子”,並且在上一篇文章談到索引碎片的時候,也知道了填充因子的重要性。盡管如此,其實我們很多的時候在建立索引,維護索引的時候並沒有對填充因子過於太多的關注。
我們本文就來說說填充因子的話題。
在討論之前,首先要聲明一下:如何要比較合理的設置填充因子,一定要知道表中的數據的使用情況,還有索引所在列的類型和特性(如是否是采用GUID,還是Identity自增,還是采用其他的生成方式)。沒有一個一蹴而就,完美的方案,一切都是隨着情況而變化的,但是分析的思路是不變的,切記。
關於填充因子的概念我們這里不做太多的討論,我們就來討論幾種需要關注填充因子的情況,同時也看看有關填充因子的一些誤區。
填充因子的誤區
以為填充因子是使用在數據插入的時候使用
這個誤區可能是很多人所犯的,因為我們知道,所謂的填充因子,就是在確定頁上面到底有多大的空間被填充,或者換句話說,也確定頁上面有多少空白被保留。那么,這個保留的空間就是為了防止我們在索引頁中插入新數據的時候發生不必要的也拆分,從而減少碎片,從而節省資源,提升性能。
相信很多的朋友都按照所講述的進行理解的,其實這是有問題的。為了使得大家更加清楚的認識這個問題,我們通過一個例子來說明下。
在下面的示例中,我們將會一個表AgileSharp_FillFactorDemo上面建立一個聚集索引,這個索引的填充因子是50%。並且在數據表建立好了之后我,我們會插入一些數據進去,然后我們通過查看sys.dm_db_index_physical_stats這個動態管理函數來看看索引頁中的空間的使用情況。
(
RowID int NOT NULL
,Column1 varchar( 500)
);
ALTER TABLE dbo.AgileSharp_FillFactorDemo ADD CONSTRAINT
PK_AgileSharp_FillFactorDemo PRIMARY KEY CLUSTERED (RowID) WITH( FILLFACTOR = 50);
WITH L1(z) AS ( SELECT 0 UNION ALL SELECT 0)
, L2(z) AS ( SELECT 0 FROM L1 a CROSS JOIN L1 b)
, L3(z) AS ( SELECT 0 FROM L2 a CROSS JOIN L2 b)
, L4(z) AS ( SELECT 0 FROM L3 a CROSS JOIN L3 b)
, L5(z) AS ( SELECT 0 FROM L4 a CROSS JOIN L4 b)
, L6(z) AS ( SELECT TOP 1000 0 FROM L5 a CROSS JOIN L5 b)
INSERT INTO dbo.AgileSharp_FillFactorDemo
SELECT ROW_NUMBER() OVER ( ORDER BY z) AS RowID, REPLICATE( ' X ', 500)
FROM L6
然后運行下面的查詢:
FROM sys.dm_db_index_physical_stats( DB_ID(), OBJECT_ID( ' dbo.AgileSharp_FillFactorDemo '), NULL, NULL, ' DETAILED ')
WHERE index_level = 0
結果如下:
相信看到結果的朋友會非常吃驚:為什么填充因子沒有起到預想的作用?
這個結果之所以沒有按照大家的想法,是因為我們的理解有誤。
其實,填充因子一開始不會在數據修改的過程中使用,而是在索引重建,重組和創建的時候使用。換句話說,就是在創建了索引,設置了填充因子之后,填充因子不會按照我們的期望發生作用,直到我們第一次重組或者重建了索引之后,此時填充因子才會起作用,而且后續的數據的修改(Insert,Update,Delete)才會使用收到填充因子的影響。
為了使得大家更加的清楚,我們還是繼續看例子。
下面,我們在表上面把索引重建,如下:
SELECT object_id, index_id, avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats( DB_ID(), OBJECT_ID( ' dbo.AgileSharp_FillFactorDemo '), NULL, NULL, ' DETAILED ')
WHERE index_level = 0
結果如下:
下面,為了證明上面的講述,我們再來看一個例子,
首先,我們還是來建立一個表,如下:
(
RowID int NOT NULL
,Column1 varchar( 500)
);
ALTER TABLE dbo.AgileSharp_FillFactorConfirm ADD CONSTRAINT
PK_AgileSharp_FillFactorConfirm PRIMARY KEY CLUSTERED (RowID) WITH( FILLFACTOR = 50);
然后我們插入數據,我們此時插入的RowID都是偶數,如下:
set @ID = 0
while @ID <= 2000
begin
set @ID = @ID + 2;
Insert into AgileSharp_FillFactorConfirm values( @ID, ' AgileSharp Confirm FillFactor ')
end

FROM sys.dm_db_index_physical_stats( DB_ID(), OBJECT_ID( ' dbo.AgileSharp_FillFactorConfirm '), NULL, NULL, ' DETAILED ')
WHERE index_level = 0

然后我們重建索引,如下:

我們插入數據,如下:
set @ID = 1
while @ID <= 2000
begin
set @ID = @ID + 2;
Insert into AgileSharp_FillFactorConfirm values( @ID, ' AgileSharp Confirm FillFactor ')
end

其實大家可以查看頁上面的詳細信息,我這里就不多說了。