Index

Ola Hallengrens 儲存過程是我們需要的並且可以安全使用嗎

  • May 29, 2018

我偶然發現了一個儲存過程,並想首先澄清一些事情,因為有人告訴我它需要“在任何伺服器上執行之前進行嚴格審查”,以及“在我們在生產伺服器上執行之前進行測試”。

我們需要了解並了解 SP 在每個階段所做的工作,以確保不引入安全風險,並且不存在數據洩露或環境不穩定的可能性。

以下是我們目前的 SP,它在周日晚上執行,但在一天之內,收益損失了,大量表的碎片率高達 99%

在此處輸入圖像描述

我們的其他表中沒有一個完全沒有填充因子,並且都設置為零(相當於 100),想知道這是否重要

在此處輸入圖像描述

請原諒我對開發人員世界非常陌生,之前沒有任何 DBA 相關問題的經驗。

我們目前的重建/重組程式碼:

/****** Object:  StoredProcedure [dbo].[IndexMaintenance_sp]    Script Date: 25/05/2018 13:05:28 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[IndexMaintenance_sp] @log_only BIT = 1
AS
BEGIN
   DECLARE @tableName VARCHAR(800)
       ,@indexName VARCHAR(800)
       ,@fragmentation FLOAT
       ,@indexId INT = 0
       ,@prevTempIndexId INT = 0
       ,@pageCount INT = 0
       ,@tableId INT
       ,@tempIndexId INT = 0;

   CREATE TABLE #tempIndexes (
       id INT IDENTITY
       ,objectId INT
       ,name VARCHAR(max)
       ,indexId INT
       );

   INSERT INTO #tempIndexes (
       objectId
       ,name
       ,indexId
       )
   SELECT i.object_id
       ,i.name AS Name
       ,i.index_id
   FROM [sys].indexes AS i
   WHERE i.name IS NOT NULL
       AND i.object_id IS NOT NULL;

   WHILE 1 = 1
   BEGIN
       SELECT @tempIndexId = id
           ,@indexId = indexId
           ,@tableId = objectId
       FROM #tempIndexes
       WHERE id = (
               SELECT min(id)
               FROM #tempIndexes
               WHERE id > @prevTempIndexId
               );

       IF @tempIndexId = @prevTempIndexId
           BREAK;

       SET @prevTempIndexId = @tempIndexId;
       SET @indexName = NULL;

       SELECT TOP 1 @tableId = s.object_id
           ,@tableName = OBJECT_NAME(s.object_id)
           ,@indexName = i.name
           ,/*s.index_id,*/ @pageCount = s.page_count /*, s.index_type_desc*/
           ,@fragmentation = s.avg_fragmentation_in_percent /*, s.fragment_count */
       FROM [sys].[dm_db_index_physical_stats](DB_ID(), @tableId, @indexId, NULL, NULL) AS s
       INNER JOIN [sys].indexes AS i ON i.object_id = s.object_id
           AND i.index_id = s.index_id
       WHERE avg_fragmentation_in_percent > 5.0
           AND s.object_id IS NOT NULL
           AND i.name IS NOT NULL;

       IF @indexName IS NULL
           CONTINUE;

       INSERT INTO [ServerHealth].[dbo].[__tblIndexFragmentation] (
           checkDate
           ,databaseId
           ,databaseName
           ,objectId
           ,objectName
           ,indexid
           ,indexName
           ,indexPages
           ,indexFragmentation
           )
       VALUES (
           GetDate()
           ,DB_ID()
           ,DB_NAME(DB_ID())
           ,@tableId
           ,@tableName
           ,@indexId
           ,@indexName
           ,@pageCount
           ,@fragmentation
           );

       IF @pageCount < 1000
           CONTINUE;

       DECLARE @sql NVARCHAR(2000);

       SET @sql = 'ALTER INDEX [' + @indexName + '] ON [dbo].[' + @tableName;

       IF @fragmentation < 30
       BEGIN
           SET @sql = @sql + '] REORGANIZE;';
       END
       ELSE
       BEGIN
           SET @sql = @sql + '] REBUILD;';
       END

       IF @log_only = 0
       BEGIN
           EXEC (@sql);
       END
   END
END
GO

要回答您的問題,是的,Ola Hallengrens 腳本備受推崇且使用安全。與任何 3rd 方工具一樣多。您如何選擇使用(或誤用)它們取決於您。確保您擁有目前版本。

如果您不確定,我可以給您的最佳建議是自己在安全的地方進行測試並形成您自己的意見。

花時間閱讀指南並了解預設設置(它們是一個很好的起點),然後自己測試它們

雖然 Olas 腳本很棒。它們不是靈丹妙藥。如果您有一張表在一天內達到 99% 的碎片,那麼您還有其他事情要做。你每天都在縮小你的數據庫嗎?

首先,如前所述,Ola 腳本是安全的,並且經過很多人的徹底測試。

如果索引只會添加到末尾並從開頭刪除(也可以使用 bigint 標識欄位),則您的填充因子應該真正設置為 100% (0)

如果您有將插入數據集中間的數據,那麼當您添加到該索引時,您將希望插入數據集的中間。如果填充因子為 100,則沒有空間,它將創建/添加到完全不合適的新記錄,從而使索引碎片化。

對於使用的正確填充因子,沒有 100% 明確的答案,並且它可以針對同一張表上的不同索引而改變。如果某些東西不斷碎片化,那麼降低填充因子可以幫助緩解這種情況。

注意降低填充因子雖然可以減少碎片,但會增加磁碟空間使用量。如果您有一個索引為 FF100 並使用 100GB 並將其更改為 FF50,那麼它現在將使用 200GB 的磁碟空間來儲存相同數量的數據。

引用自:https://dba.stackexchange.com/questions/208093