索引碎片整理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了索引碎片整理相关的知识,希望对你有一定的参考价值。

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=NUSE +@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

 

以上是关于索引碎片整理的主要内容,如果未能解决你的问题,请参考以下文章

检测和整理索引碎片

如何在 PostgreSQL 中找出碎片索引并对其进行碎片整理?

sql索引碎片产生的原理 解决碎片的办法(sql碎片整理)

SQL Server数据库表索引碎片整理

索引碎片检测和整理

SQL Server索引碎片整理实际操作记录