SQL:重建和重组索引的程序,如微软所说

时间:2017-08-04 17:48:48

标签: sql sql-server indexing database-administration shrink

我有很多目前用于插入和删除的数据库。为了维护,我创建了一个程序:

  

-Shrink数据库文件(如果已启用)

     

-Shrink数据库日志文件

     

- 搜索包含5%或更多碎片且page_count> = 1000的表的所有索引(根据this Microsoft Web about   PAGE_COUNT)

     

- 重建索引> 30%的碎片和重组索引在5%到30%之间(根据this Microsoft Web)

     

- 收集数据库的数据库日志文件

我执行三个月和每年的程序取决于使用DB。

仅当使用exec spIndexDefrag 1

指定时,数据库文件才会收缩

值0始终在开始和结束过程中缩小数据库日志文件。

目前我只在@DB_SHRINK中使用1只在某些情况下需要磁盘空间。只收缩日志文件。

安全吗?

这是我的程序,适用于任何DB,只需要在管理中选择DB。

CREATE PROCEDURE dbo.spIndexDefrag @DB_SHRINK bit
AS

DECLARE @COUNT_INDEXES INT = 1
DECLARE @TOTALTEMP_INDEXES INT
DECLARE @COUNT_TABLES INT = 1
DECLARE @TOTALTEMP_TABLES INT
DECLARE @QUERY VARCHAR (MAX) = ''
DECLARE @INDEXNAME VARCHAR (50)
DECLARE @TABLENAME VARCHAR (50)
DECLARE @FRAGMENTATION DECIMAL(18,2)
DECLARE @DBNAME VARCHAR (50) = DB_NAME()
DECLARE @LOGICALDBNAME VARCHAR (50)
DECLARE @LOGICALDBNAME_LOG VARCHAR (50)
DECLARE @QUERYSHRINK VARCHAR (300)
DECLARE @QUERYSHRINK_DB_ENABLED VARCHAR (100) = ''
DECLARE @NEWLINE AS CHAR(2) = CHAR(13) + CHAR(10)

--Nombre logico de la base de datos
SELECT @LOGICALDBNAME = name
FROM sys.master_files
WHERE database_id = db_id()
AND type = 0

--Nombre logico del log de la base de datos
SELECT @LOGICALDBNAME_LOG = name
FROM sys.master_files
WHERE database_id = db_id()
AND type = 1

--Si esta habilitado el shrink de la DB se incluye el codigo en la variable
IF @DB_SHRINK = 1
BEGIN
    SET @QUERYSHRINK_DB_ENABLED = 'DBCC SHRINKFILE('''+@LOGICALDBNAME+''', 2)'
END

--Se hace un shrink a la base de datos (Si esta disponible) y posteriormente al log
SET @QUERYSHRINK = '
ALTER DATABASE ['+@DBNAME+'] SET RECOVERY SIMPLE WITH NO_WAIT
'+@QUERYSHRINK_DB_ENABLED+'
DBCC SHRINKFILE('''+@LOGICALDBNAME_LOG+''', 2)
ALTER DATABASE ['+@DBNAME+'] SET RECOVERY FULL WITH NO_WAIT'

EXEC (@QUERYSHRINK)

/*
EL LOG DE LA BASE DE DATOS SE TRUNCA ANTES Y DESPUES 
DE REORGANIZAR Y RECONSTRUIR INDICES DE LA TABLA
*/

--Selecciono todas las tablas y vistas en la base de dato y la inserto en tabla temporal
SELECT ROW_NUMBER() OVER (Order by TABLE_NAME) AS ID, TABLE_NAME
INTO #TEMPTABLES
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE IN ('BASE TABLE','VIEW') AND TABLE_CATALOG = @DBNAME

SELECT @TOTALTEMP_TABLES = COUNT(ID) FROM #TEMPTABLES --Total de tablas y vistas

--Si existen tablas
IF @TOTALTEMP_TABLES > 0
BEGIN

    --Mientras haya tablas a verificar
    WHILE @COUNT_TABLES <= @TOTALTEMP_TABLES
    BEGIN

        --Obtengo nombre de la tabla
        SELECT @TABLENAME = TABLE_NAME FROM #TEMPTABLES WHERE ID = @COUNT_TABLES

        /*
        Busco todos los indices de la tabla que tengan 
        mas de un 5% de fragmentacion y que tengan 1000
        o mas en page_count y las inserto en tabla temporal
        */
        SELECT ROW_NUMBER() OVER (Order by avg_fragmentation_in_percent) AS ID, 
        Name, avg_fragmentation_in_percent as Fragmentation
        INTO #TEMPINDEXES 
        FROM sys.dm_db_index_physical_stats (DB_ID(), OBJECT_ID(@TABLENAME), NULL, NULL, NULL) AS a
        JOIN sys.indexes AS b ON a.object_id = b.object_id AND a.index_id = b.index_id
        WHERE name IS NOT NULL
        AND avg_fragmentation_in_percent > 5.00
        AND page_count >= 1000

        SELECT @TOTALTEMP_INDEXES = COUNT(ID) FROM #TEMPINDEXES --Total de indices en tabla

        --Si la tabla tiene indices
        IF @TOTALTEMP_INDEXES > 0
        BEGIN

            SET @COUNT_INDEXES = 1 --Reseteo contador de indices

            --Bucle que crea el query por cada indice de la tabla
            WHILE @COUNT_INDEXES <= @TOTALTEMP_INDEXES
            BEGIN
                SELECT @INDEXNAME = Name FROM #TEMPINDEXES WHERE ID = @COUNT_INDEXES
                SELECT @FRAGMENTATION = Fragmentation FROM #TEMPINDEXES WHERE ID = @COUNT_INDEXES

                /*
                Si la fragmentacion del indice es menor o igual a 30%
                entonces el indice sera reorganizado, de lo contrario
                sera reconstruido
                */
                IF @FRAGMENTATION <= 30.00 BEGIN
                    IF EXISTS (SELECT Name FROM sys.indexes WHERE name = @INDEXNAME AND object_id = OBJECT_ID(@TABLENAME))
                       BEGIN
                            SET @QUERY += 'ALTER INDEX ' +  @INDEXNAME + ' ON ' + @TABLENAME + ' REORGANIZE'  + @NEWLINE
                       END
                END
                ELSE
                BEGIN
                    IF EXISTS (SELECT Name FROM sys.indexes WHERE name = @INDEXNAME AND object_id = OBJECT_ID(@TABLENAME))
                       BEGIN
                            SET @QUERY += 'ALTER INDEX ' +  @INDEXNAME + ' ON ' + @TABLENAME + ' REBUILD' + @NEWLINE
                       END
                END

                SET @COUNT_INDEXES = @COUNT_INDEXES + 1
            END
        END

        DROP TABLE #TEMPINDEXES --Elimino tabla de indices
        SET @COUNT_TABLES = @COUNT_TABLES + 1 --Vuelvo con otra tabla el mismo proceso
    END

    EXEC (@QUERY) --Ejecuto el query creado para defragmentar indices

    DROP TABLE #TEMPTABLES --Elimino tabla de Tablas

    SET @QUERYSHRINK = REPLACE(@QUERYSHRINK,@QUERYSHRINK_DB_ENABLED,'')

    EXEC (@QUERYSHRINK) --Ejecuto el shrink del log por ultima vez pero sin shrink DB
END

GO

谢谢!

0 个答案:

没有答案