随笔-54  评论-334  文章-0  trackbacks-6
索引碎片能增大索引树的大小,增加不必要的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语句还是有得商量的地方。
posted on 2008-02-20 17:07 PerfectDesign 阅读(10814) 评论(15)  编辑 收藏

评论:
#1楼  2008-02-20 18:04 | 穆彦鹏      
赞~ 很细腻 很深入! 学习了
  回复  引用  查看    
#2楼  2008-02-20 20:40 | 蛙蛙池塘      
很专业呀,呵呵,以前没注意你的博客
  回复  引用  查看    
#3楼 [楼主] 2008-02-20 20:43 | PerfectDesign      
已经很惭愧了,比起其他发在首页的文章,我的已经是无人问津了
  回复  引用  查看    
#4楼  2008-02-20 20:46 | 蛙蛙池塘      
sql2005应该有联机索引重建的功能,但我没用过,呵呵。我觉得应该做一些job,监控索引的碎片比例,然后自动的进行索引重建,执行DBCC命令等。
  回复  引用  查看    
#5楼 [楼主] 2008-02-20 20:56 | PerfectDesign      
恩,有的,一般都有。
最后那部分代码就能做成job
  回复  引用  查看    
#6楼  2008-02-20 21:15 | ding [未注册用户]
顶一下
  回复  引用    
#7楼  2008-02-20 21:18 | 寻觅 [未注册用户]
顶一下,很好,很强大,很专业 ,值得学习

  回复  引用    
#8楼  2008-02-20 22:40 | 马可香蕉      
不错的文章
  回复  引用  查看    
#9楼  2008-02-20 23:18 | 周晓刚 [未注册用户]
太牛了
  回复  引用    
#10楼  2008-02-21 07:27 | carysun      
--引用--------------------------------------------------
PerfectDesign: 已经很惭愧了,比起其他发在首页的文章,我的已经是无人问津了
--------------------------------------------------------
无人问津是你的写的初学者懂的少啊

  回复  引用  查看    
#11楼  2008-02-21 09:13 | looklook [未注册用户]
学习了 支持楼主!
  回复  引用    
#12楼  2008-02-21 10:52 | airwolf2026      
呃,博主,可否有个要求?把你的博客模板替换一个,颜色对比度不那么大的?这样的看了眼睛难受....
  回复  引用  查看    
#13楼 [楼主] 2008-02-21 11:17 | PerfectDesign      
哈,只是觉得比较酷
  回复  引用  查看    
#15楼  2008-02-26 03:13 | fox23      
好文!
  回复  引用  查看    

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  博客园首页

  新闻频道

  社区

  小组

  博问

  网摘

  闪存

  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-02-20 17:25 编辑过
成果网帮您增加网站收入


相关链接: