문제

SQL Server 데이터베이스 개선을 위한 SSW 규칙에는 전체 데이터베이스 유지 관리 계획의 예가 있습니다. SSW.이 예에서는 Reorganize Index와 Rebuild Index, Update Statistics를 모두 실행합니다.이것에 어떤 의미가 있습니까?Reorganize Index가 Rebuild Index의 속도는 빠르지만 덜 효과적인 버전이라고 생각했나요?인덱스를 다시 작성하면 통계가 자동으로 업데이트됩니다(적어도 클러스터형 인덱스에서는).

도움이 되었습니까?

해결책

하는 일 REORGANIZE 그리고 나서 REBUILD 동일한 인덱스에 대한 변경은 의미가 없습니다. REORGANIZE 다음을 수행하면 손실이 발생합니다. REBUILD.

그보다 더 나쁜 것은 SSW의 유지 관리 계획 다이어그램에서 다음을 수행한다는 것입니다. SHRINK 첫째, 공간을 해제하는 방식의 부작용으로 인덱스를 조각화합니다.그런 다음 REBUILD 작업 중에 데이터베이스 파일에 더 많은 공간을 작업 공간으로 다시 할당합니다. REBUILD 작업.

  • REORGANIZE 추가 작업 공간을 거의 사용하지 않고 클러스터형 또는 비클러스터형 인덱스의 리프 페이지를 페이지별로 조각 모음하는 온라인 작업입니다.

  • REBUILD Enterprise 버전에서는 온라인 작업이고 다른 버전에서는 오프라인 작업이며 인덱스 크기만큼 추가 작업 공간을 다시 사용합니다.인덱스의 새 복사본을 만든 다음 이전 인덱스를 삭제하여 조각화를 제거합니다.통계는 기본적으로 이 작업의 일부로 다시 계산되지만 비활성화할 수 있습니다.

보다 인덱스 재구성 및 재구축 자세한 내용은.

사용하지 마세요 SHRINK 제외하고 TRUNCATEONLY 옵션을 선택하고 파일이 다시 커지더라도 필요한지 여부를 신중히 생각해 보아야 합니다.

sqlservercentral_SHRINKFILE

다른 팁

재구성과 재구성은 다른 것입니다.

재구성:인덱스에 대한 조각 모음입니다.기존 인덱스를 가져와 기존 페이지 조각 모음을 수행합니다.그러나 페이지가 연속된 방식이 아닌 경우 이전과 동일하게 유지됩니다.페이지의 내용만 변경됩니다.

재구축:실제로는 인덱스를 삭제하고 처음부터 다시 작성합니다.이는 조각 모음이 수행되고 인접한 페이지가 포함된 완전히 새로운 색인을 얻게 된다는 의미입니다.

또한 재구축을 사용하면 분할 또는 파일 그룹을 변경할 수 있지만 재구성을 사용하면 전체 인덱스뿐만 아니라 인덱스의 하나의 파티션만 조각 모음할 수 있습니다.

업데이트 통계는 클러스터형 인덱스에서는 자동으로 수행되지만 비클러스터형 인덱스에서는 자동으로 수행되지 않습니다.

인덱스 유지 관리를 고려하기 전에 다음 두 가지 주요 질문에 답하는 것이 중요합니다.

  1. 단편화 정도는 어느 정도인가?
  2. 적절한 조치는 무엇입니까?재구성할 것인가, 아니면 재구축할 것인가?

이 기사에 설명된 대로 http://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/, 인덱스 재구축 또는 인덱스 재구성 수행 여부를 결정하는 데 도움이 되도록 다음 사항을 이해하십시오.

  • 인덱스 재구성은 SQL Server가 기존 인덱스를 살펴보고 정리하는 프로세스입니다.인덱스 재구축은 인덱스를 삭제한 후 쌓인 조각과 빈 공간 페이지가 없는 완전히 새로운 구조로 처음부터 다시 생성하는 고강도 프로세스입니다.

  • 인덱스 재구성은 영향을 받은 테이블과 뷰를 잠그지 않고 시스템 상태를 그대로 유지하는 순수한 정리 작업인 반면, 재구축 프로세스는 전체 재구축 기간 동안 영향을 받은 테이블을 잠그므로 시스템 중단 시간이 길어질 수 있습니다. 일부 환경.이를 염두에 두고 인덱스 재구축은 '더 강력한' 솔루션을 사용하는 프로세스임이 분명하지만 영향을 받는 인덱스 테이블에 대한 장기 잠금이 발생할 수 있는 대가가 따릅니다.

반면, 인덱스 재구성은 덜 효과적인 방법으로 조각화를 해결하는 '경량' 프로세스입니다. 왜냐하면 정리된 인덱스는 완전히 처음부터 만들어진 새 인덱스 다음으로 항상 두 번째이기 때문입니다.그러나 인덱스 재구성은 작업 중에 영향을 받은 인덱스 테이블을 잠그지 않기 때문에 효율성 측면에서 훨씬 좋습니다.

위에 언급된 문서에서는 SSMS, T-SQL(테이블의 인덱스 재구성/재구축) 및 ApexSQL Backup이라는 타사 도구를 사용하여 인덱스를 재구성하고 재구축하는 방법도 설명합니다.

인덱스 재구성을 수행할 때 인덱스가 두 개 이상의 실제 파일에 분산되어 있으면 데이터는 데이터 파일 내에서만 조각 모음됩니다.페이지는 한 데이터 파일에서 다른 데이터 파일로 이동되지 않습니다.

인덱스가 단일 파일에 있는 경우 reorg 및 reindex의 최종 결과는 동일합니다.

인덱스가 얼마나 조각화되어 있는지에 따라 재구성이 더 빨라지는 경우도 있고 재색인이 더 빨라지는 경우도 있습니다.인덱스 조각화가 적을수록 재구성 속도가 빨라지고, 조각화가 많을수록 재구성 속도가 느려지지만 재색인화 속도는 빨라집니다.

정확히 무엇 비리 말했다.전체 데이터베이스를 다시 색인화하는 방법은 다음과 같습니다.

EXEC [sp_MSforeachtable] @command1="RAISERROR('DBCC DBREINDEX(''?'') ...',10,1) WITH NOWAIT DBCC DBREINDEX('?')"

나는 이 SP를 사용한다

CREATE PROCEDURE dbo.[IndexRebuild]
AS 
DECLARE @TableName NVARCHAR(500);
DECLARE @SQLIndex NVARCHAR(MAX);
DECLARE @RowCount INT;
DECLARE @Counter INT;

DECLARE @IndexAnalysis TABLE
    (
      AnalysisID INT IDENTITY(1, 1)
                     NOT NULL
                     PRIMARY KEY ,
      TableName NVARCHAR(500) ,
      SQLText NVARCHAR(MAX) ,
      IndexDepth INT ,
      AvgFragmentationInPercent FLOAT ,
      FragmentCount BIGINT ,
      AvgFragmentSizeInPages FLOAT ,
      PageCount BIGINT
    )

BEGIN
    INSERT  INTO @IndexAnalysis
            SELECT  [objects].name ,
                    'ALTER INDEX [' + [indexes].name + '] ON ['
                    + [schemas].name + '].[' + [objects].name + '] '
                    + ( CASE WHEN (   [dm_db_index_physical_stats].avg_fragmentation_in_percent >= 20
                                    AND [dm_db_index_physical_stats].avg_fragmentation_in_percent < 40
                                  ) THEN 'REORGANIZE'
                             WHEN [dm_db_index_physical_stats].avg_fragmentation_in_percent > = 40
                             THEN 'REBUILD'
                        END ) AS zSQL ,
                    [dm_db_index_physical_stats].index_depth ,
                    [dm_db_index_physical_stats].avg_fragmentation_in_percent ,
                    [dm_db_index_physical_stats].fragment_count ,
                    [dm_db_index_physical_stats].avg_fragment_size_in_pages ,
                    [dm_db_index_physical_stats].page_count
            FROM    [sys].[dm_db_index_physical_stats](DB_ID(), NULL, NULL,
                                                       NULL, 'LIMITED') AS   [dm_db_index_physical_stats]
                    INNER JOIN [sys].[objects] AS [objects] ON (   [dm_db_index_physical_stats].[object_id] = [objects].[object_id] )
                    INNER JOIN [sys].[schemas] AS [schemas] ON ( [objects].[schema_id]  = [schemas].[schema_id] )
                    INNER JOIN [sys].[indexes] AS [indexes] ON (  [dm_db_index_physical_stats].[object_id] = [indexes].[object_id]
                                                          AND  [dm_db_index_physical_stats].index_id = [indexes].index_id
                                                          )
            WHERE   index_type_desc <> 'HEAP'
                    AND [dm_db_index_physical_stats].avg_fragmentation_in_percent > 20
END

SELECT  @RowCount = COUNT(AnalysisID)
FROM    @IndexAnalysis

SET @Counter = 1
WHILE @Counter <= @RowCount 
    BEGIN

        SELECT  @SQLIndex = SQLText
        FROM    @IndexAnalysis
        WHERE   AnalysisID = @Counter

        EXECUTE sp_executesql @SQLIndex

        SET @Counter = @Counter + 1

    END
 GO

매주 이 SP를 실행하는 하나의 작업을 생성합니다.

더 좋은 점은 다음과 같습니다.

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REINDEX'

또는

EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REORGANIZE'

내 2센트...이 방법은 tech net에 설명된 사양을 따릅니다. http://technet.microsoft.com/en-us/library/ms189858(v=sql.105).aspx

USE [MyDbName]
GO

SET ANSI_NULLS OFF
GO

SET QUOTED_IDENTIFIER OFF
GO

CREATE PROCEDURE [maintenance].[IndexFragmentationCleanup]
AS
DECLARE @reIndexRequest VARCHAR(1000)

DECLARE reIndexList CURSOR
FOR
SELECT INDEX_PROCESS
FROM (
    SELECT CASE 
            WHEN avg_fragmentation_in_percent BETWEEN 5
                    AND 30
                THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REORGANIZE;'
            WHEN avg_fragmentation_in_percent > 30
                THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REBUILD with(ONLINE=ON);'
            END AS INDEX_PROCESS
        ,avg_fragmentation_in_percent
        ,t.NAME
    FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, NULL) AS a
    INNER JOIN sys.indexes AS i ON a.object_id = i.object_id
        AND a.index_id = i.index_id
    INNER JOIN sys.tables t ON t.object_id = i.object_id
    WHERE i.NAME IS NOT NULL
    ) PROCESS
WHERE PROCESS.INDEX_PROCESS IS NOT NULL
ORDER BY avg_fragmentation_in_percent DESC

OPEN reIndexList

FETCH NEXT
FROM reIndexList
INTO @reIndexRequest

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY

        PRINT @reIndexRequest;

        EXEC (@reIndexRequest);

    END TRY

    BEGIN CATCH
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = 'UNABLE TO CLEAN UP INDEX WITH: ' + @reIndexRequest + ': MESSAGE GIVEN: ' + ERROR_MESSAGE()
            ,@ErrorSeverity = 9 
            ,@ErrorState = ERROR_STATE();

    END CATCH;

    FETCH NEXT
    FROM reIndexList
    INTO @reIndexRequest
END

CLOSE reIndexList;

DEALLOCATE reIndexList;

RETURN 0

GO

웹서핑을 하다가 좋은 글을 발견했습니다.그리고 나는 데이터베이스의 모든 인덱스를 재구성, 재생성 또는 재구축하는 함수와 스크립트를 아래에 작성했습니다.

먼저 읽어야 할 수도 있습니다. 이 기사 왜 우리가 모든 인덱스를 다시 생성하지 않는지 이해합니다.

두 번째로 인덱스에 대한 생성 스크립트를 작성하는 함수가 필요합니다.그래서 이 기사 도움이 될 수 있습니다.또한 아래에서 작업 기능을 공유하고 있습니다.

데이터베이스의 모든 인덱스를 찾고 구성하기 위해 while 루프를 만드는 마지막 단계입니다. 이 비디오 이것을 만드는 훌륭한 예입니다.

기능:

create function GetIndexCreateScript(
    @index_name nvarchar(100)
) 
returns nvarchar(max)
as
begin

declare @Return   varchar(max)

SELECT @Return = ' CREATE ' + 
    CASE WHEN I.is_unique = 1 THEN ' UNIQUE ' ELSE '' END  +  
    I.type_desc COLLATE DATABASE_DEFAULT +' INDEX ' +   
    I.name  + ' ON '  +  
    Schema_name(T.Schema_id)+'.'+T.name + ' ( ' + 
    KeyColumns + ' )  ' + 
    ISNULL(' INCLUDE ('+IncludedColumns+' ) ','') + 
    ISNULL(' WHERE  '+I.Filter_definition,'') + ' WITH ( ' + 
    CASE WHEN I.is_padded = 1 THEN ' PAD_INDEX = ON ' ELSE ' PAD_INDEX = OFF ' END + ','  + 
    'FILLFACTOR = '+CONVERT(CHAR(5),CASE WHEN I.Fill_factor = 0 THEN 100 ELSE I.Fill_factor END) + ','  + 
    -- default value 
    'SORT_IN_TEMPDB = OFF '  + ','  + 
    CASE WHEN I.ignore_dup_key = 1 THEN ' IGNORE_DUP_KEY = ON ' ELSE ' IGNORE_DUP_KEY = OFF ' END + ','  + 
    CASE WHEN ST.no_recompute = 0 THEN ' STATISTICS_NORECOMPUTE = OFF ' ELSE ' STATISTICS_NORECOMPUTE = ON ' END + ','  + 
    -- default value  
    ' DROP_EXISTING = ON '  + ','  + 
    -- default value  
    ' ONLINE = OFF '  + ','  + 
   CASE WHEN I.allow_row_locks = 1 THEN ' ALLOW_ROW_LOCKS = ON ' ELSE ' ALLOW_ROW_LOCKS = OFF ' END + ','  + 
   CASE WHEN I.allow_page_locks = 1 THEN ' ALLOW_PAGE_LOCKS = ON ' ELSE ' ALLOW_PAGE_LOCKS = OFF ' END  + ' ) ON [' + 
   DS.name + ' ] '  
FROM sys.indexes I   
 JOIN sys.tables T ON T.Object_id = I.Object_id    
 JOIN sys.sysindexes SI ON I.Object_id = SI.id AND I.index_id = SI.indid   
 JOIN (SELECT * FROM (  
    SELECT IC2.object_id , IC2.index_id ,  
        STUFF((SELECT ' , ' + C.name + CASE WHEN MAX(CONVERT(INT,IC1.is_descending_key)) = 1 THEN ' DESC ' ELSE ' ASC ' END 
    FROM sys.index_columns IC1  
    JOIN Sys.columns C   
       ON C.object_id = IC1.object_id   
       AND C.column_id = IC1.column_id   
       AND IC1.is_included_column = 0  
    WHERE IC1.object_id = IC2.object_id   
       AND IC1.index_id = IC2.index_id   
    GROUP BY IC1.object_id,C.name,index_id  
    ORDER BY MAX(IC1.key_ordinal)  
       FOR XML PATH('')), 1, 2, '') KeyColumns   
    FROM sys.index_columns IC2   
    --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables  
    GROUP BY IC2.object_id ,IC2.index_id) tmp3 )tmp4   
  ON I.object_id = tmp4.object_id AND I.Index_id = tmp4.index_id  
 JOIN sys.stats ST ON ST.object_id = I.object_id AND ST.stats_id = I.index_id   
 JOIN sys.data_spaces DS ON I.data_space_id=DS.data_space_id   
 JOIN sys.filegroups FG ON I.data_space_id=FG.data_space_id   
 LEFT JOIN (SELECT * FROM (   
    SELECT IC2.object_id , IC2.index_id ,   
        STUFF((SELECT ' , ' + C.name  
    FROM sys.index_columns IC1   
    JOIN Sys.columns C    
       ON C.object_id = IC1.object_id    
       AND C.column_id = IC1.column_id    
       AND IC1.is_included_column = 1   
    WHERE IC1.object_id = IC2.object_id    
       AND IC1.index_id = IC2.index_id    
    GROUP BY IC1.object_id,C.name,index_id   
       FOR XML PATH('')), 1, 2, '') IncludedColumns    
   FROM sys.index_columns IC2    
   --WHERE IC2.Object_id = object_id('Person.Address') --Comment for all tables   
   GROUP BY IC2.object_id ,IC2.index_id) tmp1   
   WHERE IncludedColumns IS NOT NULL ) tmp2    
ON tmp2.object_id = I.object_id AND tmp2.index_id = I.index_id   
WHERE I.is_primary_key = 0 AND I.is_unique_constraint = 0 
AND I.[name] = @index_name

return @Return

end

한동안 SQL :

declare @RebuildIndex Table(
    IndexId int identity(1,1),
    IndexName varchar(100),
    TableSchema varchar(50),
    TableName varchar(100),
    Fragmentation decimal(18,2)
)


insert into @RebuildIndex (IndexName,TableSchema,TableName,Fragmentation)
SELECT 
    B.[name] as 'IndexName', 
    Schema_Name(O.[schema_id]) as 'TableSchema',
    OBJECT_NAME(A.[object_id]) as 'TableName',
    A.[avg_fragmentation_in_percent] Fragmentation
FROM sys.dm_db_index_physical_stats(db_id(),NULL,NULL,NULL,'LIMITED') A 
INNER JOIN sys.indexes B ON A.[object_id] = B.[object_id] and A.index_id = B.index_id  
INNER JOIN sys.objects O ON O.[object_id] = B.[object_id]  
 where B.[name] is not null and B.is_primary_key = 0 AND B.is_unique_constraint = 0 and A.[avg_fragmentation_in_percent] >= 5  

--select * from @RebuildIndex

 declare @begin int = 1
 declare @max int
 select @max = Max(IndexId) from @RebuildIndex
 declare @IndexName varchar(100), @TableSchema varchar(50), @TableName varchar(100) , @Fragmentation decimal(18,2)

 while @begin <= @max
 begin

    Select @IndexName = IndexName from @RebuildIndex where IndexId = @begin
    select @TableSchema = TableSchema  from @RebuildIndex where IndexId = @begin
    select @TableName = TableName  from @RebuildIndex where IndexId = @begin 
    select @Fragmentation = Fragmentation  from @RebuildIndex where IndexId = @begin 

    declare @sql nvarchar(max)
    if @Fragmentation < 31
    begin
        set @sql = 'ALTER INDEX ['+@IndexName+'] ON ['+@TableSchema+'].['+@TableName+'] REORGANIZE WITH ( LOB_COMPACTION = ON )'
        print 'Reorganized Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
    end
    else
    begin
        set @sql = (select dbo.GetIndexCreateScript(@IndexName))
        if(@sql is not null)
        begin
            print 'Recreated Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
        end 
        else
        begin
            set @sql = 'ALTER INDEX ['+@IndexName+'] ON ['+@TableSchema+'].['+@TableName+'] REBUILD PARTITION = ALL WITH (ONLINE = ON)'
            print 'Rebuilded Index ' + @IndexName + ' for ' + @TableName + ' Fragmentation was ' + convert(nvarchar(18),@Fragmentation)
        end
    end

    execute(@sql)


    set @begin = @begin+1

end
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top