您的位置:首页 > 其它

索引碎片整理

2016-01-27 17:36 225 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: