索引碎片能增大索引树的大小,增加不必要的IO,所以每隔一段时间对索引碎片进行检查时很有必要的。
下面一个示例一起来分析如何将索引降至最低。

新建一个表:
如何将索引碎片数量降至最低create table t3
如何将索引碎片数量降至最低(
如何将索引碎片数量降至最低
int primary key,
如何将索引碎片数量降至最低xx 
varchar(200not null
如何将索引碎片数量降至最低)

加入数据:
如何将索引碎片数量降至最低declare @x int
如何将索引碎片数量降至最低
set @x = 0
如何将索引碎片数量降至最低
while @x <1000
如何将索引碎片数量降至最低
begin                       
如何将索引碎片数量降至最低
insert into t3 values (@x,'qweasdqweasdqweasdqweqweasdqwe')
如何将索引碎片数量降至最低
set @x = @x+1
如何将索引碎片数量降至最低
end

执行动态管理视图:
如何将索引碎片数量降至最低SELECT index_id,index_type_desc,avg_fragmentation_in_percent,page_count FROM sys.dm_db_index_physical_stats(db_id(), OBJECT_ID('t3'), NULLNULL , 'LIMITED');
如何将索引碎片数量降至最低

可以看到:
如何将索引碎片数量降至最低

index_id为0表示这个是堆,平均的碎片有33%

现在执行几个可以减少碎片的方法都不管用,不能减少碎片。
包括:
如何将索引碎片数量降至最低DBCC INDEXDEFRAG (test, 'dbo.t3', PK__t3__0EA330E9)
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
alter index PK__t3__0EA330E9 on t3
如何将索引碎片数量降至最低rebuild
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
dbcc dbreindex ('t3')
如何将索引碎片数量降至最低
这几个方法还有删除重建索引,都不能减少碎片数量。

后来我觉得是因为数据太少了,导致页也很少,数据库可能存在某种智能,判断是否值得去做重建索引的工作,所以加大的数据量:
如何将索引碎片数量降至最低declare @x int
如何将索引碎片数量降至最低
set @x = 1000
如何将索引碎片数量降至最低
while @x <10000
如何将索引碎片数量降至最低
begin                       
如何将索引碎片数量降至最低
insert into t3 values (@x,'qweasdqweasdqweasdqweqweasdqwe')
如何将索引碎片数量降至最低
set @x = @x+1
如何将索引碎片数量降至最低
end

再执行语句:
如何将索引碎片数量降至最低SELECT index_id,index_type_desc,avg_fragmentation_in_percent,page_count FROM sys.dm_db_index_physical_stats(db_id(), OBJECT_ID('t3'), NULLNULL , 'LIMITED');
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
alter index t3index on t3
如何将索引碎片数量降至最低rebuild


显示出来了!
如何将索引碎片数量降至最低

结论:
SQL Server在执行相关的操作的时候都会智能去判断是否值得去做,比如在页面数太小的情况下可以不去重建索引,rebuild reindex 。类似的,在SQL Server 2005 里面也多了许多智能的判断来保证一个完整庞大而又不失智能的设计,
比如:
生成查询计划的阀值
缓存机制,缓存的筛选,LRU算法
预读机制
checkpoint减少回滚距离
智能join判断
重编译

了解SQL Server这种类似的软件产品能够为我们在设计产品的时候提供更多的思路想法,即使你了解上面的东西对你的SQL开发也不会有太多帮助。

另外附上几种方式的区别:
reindex是比较好的选择,速度快,但是他不能在线操作
INDEXDEFRAG 比较慢,但是可以在线操作
rebuild建议在碎片较少时采用。

附上微软的重建索引脚本,从里面也可以看出微软根据碎片大小推荐的方式,不过这个要随每个不同的数据库而定。
如何将索引碎片数量降至最低-- ensure a USE <databasename> statement has been executed first.
如何将索引碎片数量降至最低
SET NOCOUNT ON;
如何将索引碎片数量降至最低
DECLARE @objectid int;
如何将索引碎片数量降至最低
DECLARE @indexid int;
如何将索引碎片数量降至最低
DECLARE @partitioncount bigint;
如何将索引碎片数量降至最低
DECLARE @schemaname sysname;
如何将索引碎片数量降至最低
DECLARE @objectname sysname;
如何将索引碎片数量降至最低
DECLARE @indexname sysname;
如何将索引碎片数量降至最低
DECLARE @partitionnum bigint;
如何将索引碎片数量降至最低
DECLARE @partitions bigint;
如何将索引碎片数量降至最低
DECLARE @frag float;
如何将索引碎片数量降至最低
DECLARE @command varchar(8000);
如何将索引碎片数量降至最低
-- ensure the temporary table does not exist
如何将索引碎片数量降至最低
IF EXISTS (SELECT name FROM sys.objects WHERE name = 'work_to_do')
如何将索引碎片数量降至最低    
DROP TABLE work_to_do;
如何将索引碎片数量降至最低
-- conditionally select from the function, converting object and index IDs to names.
如何将索引碎片数量降至最低
SELECT
如何将索引碎片数量降至最低    
object_id AS objectid,
如何将索引碎片数量降至最低    index_id 
AS indexid,
如何将索引碎片数量降至最低    partition_number 
AS partitionnum,
如何将索引碎片数量降至最低    avg_fragmentation_in_percent 
AS frag
如何将索引碎片数量降至最低
INTO work_to_do
如何将索引碎片数量降至最低
FROM sys.dm_db_index_physical_stats (DB_ID(), NULLNULL , NULL'LIMITED')
如何将索引碎片数量降至最低
WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;
如何将索引碎片数量降至最低
-- Declare the cursor for the list of partitions to be processed.
如何将索引碎片数量降至最低
DECLARE partitions CURSOR FOR SELECT * FROM work_to_do;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
-- Open the cursor.
如何将索引碎片数量降至最低
OPEN partitions;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
-- Loop through the partitions.
如何将索引碎片数量降至最低
FETCH NEXT
如何将索引碎片数量降至最低   
FROM partitions
如何将索引碎片数量降至最低   
INTO @objectid@indexid@partitionnum@frag;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
WHILE @@FETCH_STATUS = 0
如何将索引碎片数量降至最低    
BEGIN;
如何将索引碎片数量降至最低        
SELECT @objectname = o.name, @schemaname = s.name
如何将索引碎片数量降至最低        
FROM sys.objects AS o
如何将索引碎片数量降至最低        
JOIN sys.schemas as s ON s.schema_id = o.schema_id
如何将索引碎片数量降至最低        
WHERE o.object_id = @objectid;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低        
SELECT @indexname = name 
如何将索引碎片数量降至最低        
FROM sys.indexes
如何将索引碎片数量降至最低        
WHERE  object_id = @objectid AND index_id = @indexid;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低        
SELECT @partitioncount = count (*
如何将索引碎片数量降至最低        
FROM sys.partitions
如何将索引碎片数量降至最低        
WHERE object_id = @objectid AND index_id = @indexid;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding
如何将索引碎片数量降至最低
IF @frag < 30.0
如何将索引碎片数量降至最低    
BEGIN;
如何将索引碎片数量降至最低    
SELECT @command = 'ALTER INDEX ' + @indexname + ' ON ' + @schemaname + '.' + @objectname + ' REORGANIZE';
如何将索引碎片数量降至最低    
IF @partitioncount > 1
如何将索引碎片数量降至最低        
SELECT @command = @command + ' PARTITION=' + CONVERT (CHAR@partitionnum);
如何将索引碎片数量降至最低    
EXEC (@command);
如何将索引碎片数量降至最低    
END;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
IF @frag >= 30.0
如何将索引碎片数量降至最低    
BEGIN;
如何将索引碎片数量降至最低    
SELECT @command = 'ALTER INDEX ' + @indexname +' ON ' + @schemaname + '.' + @objectname + ' REBUILD';
如何将索引碎片数量降至最低    
IF @partitioncount > 1
如何将索引碎片数量降至最低        
SELECT @command = @command + ' PARTITION=' + CONVERT (CHAR@partitionnum);
如何将索引碎片数量降至最低    
EXEC (@command);
如何将索引碎片数量降至最低    
END;
如何将索引碎片数量降至最低
PRINT 'Executed ' + @command;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
FETCH NEXT FROM partitions INTO @objectid@indexid@partitionnum@frag;
如何将索引碎片数量降至最低
END;
如何将索引碎片数量降至最低
-- Close and deallocate the cursor.
如何将索引碎片数量降至最低
CLOSE partitions;
如何将索引碎片数量降至最低
DEALLOCATE partitions;
如何将索引碎片数量降至最低
如何将索引碎片数量降至最低
-- drop the temporary table
如何将索引碎片数量降至最低
IF EXISTS (SELECT name FROM sys.objects WHERE name = 'work_to_do')
如何将索引碎片数量降至最低    
DROP TABLE work_to_do;
如何将索引碎片数量降至最低
GO

BOL的推荐:
avg_fragmentation_in_percent 修复语句

> 5% 且 < = 30%

ALTER INDEX REORGANIZE

> 30%

ALTER INDEX REBUILD WITH (ONLINE = ON)*

小于5没必要重建,所以上面的SQL语句还是有得商量的地方。

相关文章:

  • 2022-12-23
  • 2021-12-10
  • 2021-05-20
  • 2021-12-20
  • 2022-03-05
  • 2022-02-23
  • 2022-02-11
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-11-27
  • 2021-11-20
  • 2022-02-09
  • 2021-07-03
相关资源
相似解决方案