Nivel de Fragmentacion de una base de dato
Nivel de Fragmentación
Uno de los principales tópicos que se debe verificar es el crecimiento de los archivos que componen una base de datos, como así también el nivel de fragmentación de los índices que la componen.
Asegurar el mejor rendimiento de una base de datos en MSSQL Server puede ser una tarea labiosa.
Verifica que bases de datos crecieron de manera automática
Cuando alguno de los archivos que componen la base (mdf y ldf) se queden sin espacios, y tiene permitido autocrecer (autogrowth) detienen la consulta en curso, y autoincrementa su tamaño, y continua con la operación inicial. Esto si ocurre muy seguido puede provocar que se reduzca el rendimiento de la base.
Una forma de detectarlo es consultando el log del SQL Server:
SELECT DatabaseName as Base, [FileName] as Archivo, CASE EventClass WHEN 92 THEN 'Datos' WHEN 93 THEN 'Log' END as Tipo, CONVERT(VARCHAR(20), EndTime - StartTime, 114) as TiempoDemora, StartTime as FechaInicio, EndTime as FechaFin FROM ( SELECT pt = REVERSE(SUBSTRING(REVERSE([path]), CHARINDEX('\', REVERSE([path])), 260)) + N'log.trc' FROM sys.traces WHERE is_default = 1 ) p CROSS APPLY sys.fn_trace_gettable(pt, DEFAULT) WHERE EventClass IN (92, 93) ORDER BY StartTime DESC
De acuerdo al resultado será la base en la que deberemos trabajar:
- Si aparece la TEMPDB la opción mas recomendable es: Crear un archivos de Datos (.MDF) y un archivo de LOG( ldf) por cada procesador que tiene el servidor. Y el tamaño inicial total de la base debe ser el actual + 10% . Y luego irlo ajustando a medida que se vaya necesitando.
Verifica el nivel de fragmentación de los indices
El segundo punto importante es verificar que nivel de fragmentación tienen cada uno de los indices que componen la base de datos. Este punto puede provocar que nuestra base de datos tenga un tamaño mayor que el real. Y provoque que las consultas se demoren un poco mas de lo que deberian:
Para corroborarlo podemos usar el siguiente script:
IF OBJECT_ID('tempdb.dbo.#temp') IS NOT NULL DROP TABLE #temp GO CREATE TABLE #temp ( db SYSNAME DEFAULT DB_NAME(), flname SYSNAME, size_after_growth DECIMAL(18,2), size DECIMAL(18,2), space_used DECIMAL(18,2), growth INT, is_percent_growth BIT, PRIMARY KEY CLUSTERED (db, flname) ) DECLARE @SQL NVARCHAR(MAX) SELECT @SQL = STUFF(( SELECT ' USE [' + name + '] INSERT INTO #temp (flname, size_after_growth, space_used, size, growth, is_percent_growth) SELECT name , CASE WHEN is_percent_growth = 1 THEN size * (1 + (growth / 100.)) ELSE size + growth END * 8. / 1024 , space_used = FILEPROPERTY(name, ''SpaceUsed'') * 8. / 1024 , size = size * 8. / 1024 , CASE WHEN is_percent_growth = 1 THEN growth ELSE growth * 8. / 1024 END , is_percent_growth FROM sys.database_files' FROM sys.databases WHERE [state] = 0 FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') EXEC sys.sp_executesql @SQL SELECT db , flname , size_after_growth , size , space_used , CAST(growth AS VARCHAR(10)) + CASE WHEN is_percent_growth = 1 THEN ' %' ELSE ' MB' END FROM #temp WHERE (is_percent_growth = 0 AND growth < 50) OR (is_percent_growth = 1 AND growth < 5) OR (size - space_used < 20)
Para correguirlo podemos ejecutar el siguiente script por cada una de nuestras bases de datos:
DECLARE @SQL NVARCHAR(MAX) SELECT @SQL = ( SELECT ' ALTER INDEX [' + i.name + N'] ON [' + SCHEMA_NAME(o.[schema_id]) + '].[' + o.name + '] ' + CASE WHEN s.avg_fragmentation_in_percent > 30 THEN 'REBUILD' ELSE 'REORGANIZE' END + '; ' FROM ( SELECT s.[object_id] , s.index_id , avg_fragmentation_in_percent = MAX(s.avg_fragmentation_in_percent) FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) s WHERE s.page_count > 128 -- > 1 MB AND s.index_id > 0 -- <> HEAP AND s.avg_fragmentation_in_percent > 5 GROUP BY s.[object_id], s.index_id ) s JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id JOIN sys.objects o ON o.[object_id] = s.[object_id] FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') PRINT @SQL EXEC sys.sp_executesql @SQL