首页 > 数据库 > SQL Server > 正文

怎样将索引碎片数量降至最低

2024-08-31 00:46:59
字体:
来源:转载
供稿:网友
索引碎片能增大索引树的大小,增加不必要的IO,所以每隔一段时间对索引碎片进行检查时很有必要的。
下面一个示例一起来分析如何将索引降至最低。

新建一个表:
create table t3
(
i int primary key,
xx varchar(200) not null
)

加入数据:
declare @x int
set @x = 0while @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'), NULL, NULL , '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'), NULL, NULL , '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(), NULL, NULL , 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语句还是有得商量的地方。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表