我有很多目前用于插入和删除的数据库。为了维护,我创建了一个程序:
-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
谢谢!