索引碎片整理
USE [DBA_Maintenance] IF EXISTS(SELECT 1 FROM sysobjects WHERE xtype='P' AND name = 'USP_Auto_IndexDefrag') BEGIN DROP PROCEDURE USP_Auto_IndexDefrag END GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[USP_Auto_IndexDefrag] @Db_name nvarchar(256) WITH ENCRYPTION AS BEGIN SET NOCOUNT ON declare @dbname nvarchar(256) ,@dbname_cur nvarchar(256) ,@SchemaName nvarchar(256) ,@TableName Nvarchar(256) ,@IndexName Nvarchar(512) ,@PctFrag decimal ,@Defrag nvarchar(max) DECLARE @SQL_TMP_SUB NVARCHAR(MAX) DECLARE @SQL_TMP NVARCHAR(MAX) set @dbname=@Db_name set @Db_name=N'['+@Db_name+']' if exists(select 1 from sys.objects where object_id =object_id(N'#tmp')) Drop table #tmp; if exists(select 1 from sys.objects where object_id =object_id(N'#tmp_sub')) Drop table #tmp_sub; create table #tmp_sub(database_id int,dbname nvarchar(32),tablename nvarchar(128),index_type_desc nvarchar(128)) create clustered index ix_sub_db_id_tb_name_indexname on #tmp_sub(database_id,tablename,index_type_desc) create table #tmp(database_id int,dbname nvarchar(256),tablename nvarchar(256),indexname nvarchar(256),type_desc nvarchar(128),schemaname nvarchar(256),avgfragment decimal) create clustered index ix_db_id_tb_name_indexname on #tmp(database_id,tablename,type_desc) SET @SQL_TMP_SUB=N'USE' +@db_name+CHAR(13)+CHAR(10)+ 'insert into #tmp_sub(database_id,dbname,tablename,index_type_desc) select distinct c.database_id,c.name as dbname,b.name,''CLUSTERED'' from sys.dm_db_index_physical_stats(DB_ID('''+@dbname+'''),NULL,NULL,NULL,''SAMPLED'') as a join sys.tables as b on a.object_id=b.object_id join sys.databases as c on a.database_id=c.database_id join sys.all_columns d on d.object_id =a.object_id join sys.sysobjects e on d.object_id=e.id and e.xtype=''U'' join sys.types f on d.user_type_id=f.user_type_id where b.type_desc=''USER_TABLE'' and b.is_ms_shipped=0 and (d.max_length =-1 OR (f.name in (''image'',''text'',''ntext'',''xml'',''varbinary'',''binary'')))'+CHAR(13)+CHAR(10)+'' EXEC SP_EXECUTESQL @SQL_TMP_SUB, N'@Db_name nvarchar(256),@dbname nvarchar(256)',@Db_name,@dbname SET @SQL_TMP=N' USE' +@db_name+CHAR(13)+CHAR(10)+ 'insert into #tmp(database_id,dbname,tablename,indexname,type_desc,schemaname,avgfragment) select distinct d.database_id,d.name as dbname,c.name,b.name,b.type_desc,e.name,a.avg_fragmentation_in_percent from sys.dm_db_index_physical_stats(DB_ID('''+@dbname+'''),NULL,NULL,NULL,''SAMPLED'') as a join sys.indexes as b on a.object_id=b.object_id and a.index_id=b.index_id join sys.tables as c on a.object_id=c.object_id join sys.databases as d on a.database_id=d.database_id join sys.schemas as e on c.schema_id=e.schema_id join sys.sysobjects f on c.object_id=f.id join sys.all_columns g on f.id=g.object_id join sys.types h on g.user_type_id=h.user_type_id where a.avg_fragmentation_in_percent >20 and c.type=''U'' and f.xtype=''U'' and c.is_ms_shipped=0 '+CHAR(13)+CHAR(10)+'' EXEC SP_EXECUTESQL @SQL_TMP, N'@Db_name nvarchar(256),@dbname nvarchar(256)',@Db_name,@dbname ----------脱机重建索引 declare @i_cur int=1 declare @count int=0 select @count=count(*) from #tmp where exists (select 1 from #tmp_sub b where database_id=b.database_id and tablename=b.tablename and type_desc=b.index_type_desc) if @count>=1 begin while @i_cur<@count begin select @dbname_cur=dbname,@TableName=tablename,@IndexName=indexname,@SchemaName=schemaname,@PctFrag=avgfragment from ( select row_number() over(order by indexname)rn,dbname,tablename,indexname, schemaname,avgfragment from #tmp where exists (select 1 from #tmp_sub b where database_id=b.database_id and tablename=b.tablename and type_desc=b.index_type_desc) )ta where rn=@i_cur if @PctFrag between 20.0 and 40.0 begin set @Defrag=N' ALTER INDEX ['+@IndexName+'] ON ['+@dbname_cur+'].['+@SchemaName+'].['+ @TableName +'] REORGANIZE'--重新组织索引页不删除索引 EXEC SP_EXECUTESQL @Defrag end else if @PctFrag>40.0 begin SET @Defrag=N' ALTER INDEX ['+@IndexName+'] ON ['+@dbname_cur+'].['+@SchemaName+'].['+ @TableName +'] REBUILD WITH (ONLINE = OFF )'--脱机重建索引。 EXEC SP_EXECUTESQL @Defrag end set @i_cur=@i_cur+1 end end ----------联机重建索引 declare @n_count int=0 declare @n_i int=1 select @count=count(*) from #tmp where not exists (select 1 from #tmp_sub b where database_id=b.database_id and tablename=b.tablename and type_desc=b.index_type_desc) if @count>=1 begin WHILE @n_i<@count begin select @dbname_cur=dbname,@TableName=tablename,@IndexName=indexname,@SchemaName=schemaname,@PctFrag=avgfragment from ( select row_number() over(order by indexname)rn,dbname,tablename,indexname, schemaname,avgfragment from #tmp where not exists (select 1 from #tmp_sub b where database_id=b.database_id and tablename=b.tablename and type_desc=b.index_type_desc) )tb where rn=@n_i if @PctFrag between 20.0 and 40.0 begin set @Defrag=N' ALTER INDEX ['+@IndexName+'] ON ['+@dbname_cur+'].['+@SchemaName+'].['+ @TableName +'] REORGANIZE'--重新组织索引页不删除索引 EXEC SP_EXECUTESQL @Defrag end else if @PctFrag>40.0 begin SET @Defrag=N' ALTER INDEX ['+@IndexName+'] ON ['+@dbname_cur+'].['+@SchemaName+'].['+ @TableName +'] REBUILD WITH (ONLINE = ON )'--联机重建索引。即不锁定表重新创建索引 EXEC SP_EXECUTESQL @Defrag end set @n_i=@n_i+1 end end truncate table #tmp truncate table #tmp_sub drop table #tmp drop table #tmp_sub SET NOCOUNT OFF END