Introducción
Aparte de numerosos factores, un mantenimiento pobre del índice puede ser una razón para el desempeño disminuido de SQL Server. Si una base de datos contiene tablas con numerosas entradas, y eso es actualizado constantemente, es muy probable que ocurra una alta fragmentación del índice. Para índices más pequeños, la alta fragmentación no necesariamente degrada el desempeño de las consultas que son corridas sobre una tabla. Pero para tablas más grandes, con índices que consisten en 1000 páginas o más, la fragmentación podría causar problemas notorios de desempeño. Afortunadamente, realizar tareas de mantenimiento de índices regularmente puede eliminar el riesgo de degradar el desempeño significativamente. Las formas más efectivas de tratar la fragmentación del índice son las operaciones de reorganizar y reconstruir el índice.
Para bases de datos más pequeñas, las tareas de mantenimiento del índice pueden ser ejecutadas manualmente, cuando la necesidad emerge. Instrucciones detalladas para correr trabajos de reorganización y reconstrucción manualmente pueden ser encontradas en este artículo: Por qué, cuándo y cómo reconstruir y reorganizar índices de SQL Server. Pero las bases de datos más grandes y de alto tráfico requieren mantenimiento de índices de forma regular: semanalmente o, incluso, diariamente. Para estos casos de uso, es prudente configurar una política que correrá automáticamente según el programa establecido por el DBA.
Este artículo muestra tres soluciones para crear una política completamente funcional de desfragmentación de SQL Server:
-
Configurando la política como un trabajo de SQL Server Agent – esto requiere ciertas habilidades con las consultas y algún conocimiento básico de T-SQL. Aunque un poco compleja, esta opción es la más personalizable. El servicio de SQL Server Agent necesita ser instalado y debe estar corriendo.
-
Usando un plan de mantenimiento en SQL Server Management Studio – esta opción es un poco más amigable para el usuario, pero no permite al usuario desfragmentar un índice específico. La desfragmentación es permitida sólo al nivel de tablas. Esta opción también requiere que SQL Server Agent esté instalado en el servidor.
-
Usando políticas de ApexSQL Defrag – ApexSQL Defrag es una solución de terceros simple pero poderosa para la administración de fragmentación de índices en SQL Server. Todas las operaciones están definidas y desplegadas en la interfaz gráfica de usuario y no requieren el uso de T-SQL o SQL Server Agent.
Detectando la fragmentación del índice en SQL Server
Antes de aplicar cualquiera de las soluciones listadas, es necesario correr un análisis de índice primero para detectar índices altamente fragmentados. Correr un trabajo de reorganización o reconstrucción en cada índice de base de datos, esquema o tabla puede sonar como la solución más fácil, pero no es recomendado, dado que puede consumir mucho tiempo y recursos. La mejor manera de verificar la fragmentación del índice en SQL Server es usar la función integrada sys.dm_db_index_physical_stats. Esta función retorna la información de tamaño y fragmentación para todos los índices en un servidor, todos los índices en una base de datos, todos los índices en una tabla, o sólo un índice, dependiendo de los parámetros provistos. Consultar la función en crudo con parámetros básicos debería recolectar toda la información necesaria para el análisis, pero los resultados estarán muy desordenados. Por lo tanto, usamos la consulta modificada:
--Script 1: Detecting index fragmentation SELECT dbschemas.[name] AS 'Schema', dbtables.[name] AS 'Table', dbindexes.[name] AS 'Index', indexstats.avg_fragmentation_in_percent AS 'Frag (%)', indexstats.page_count AS 'Page count' FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats INNER JOIN sys.tables dbtables ON dbtables.[object_id] = indexstats.[object_id] INNER JOIN sys.schemas dbschemas ON dbtables.[schema_id] = dbschemas.[schema_id] INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id] AND indexstats.index_id = dbindexes.index_id WHERE indexstats.database_id = DB_ID() ORDER BY indexstats.avg_fragmentation_in_percent DESC
Correr la consulta en la base de datos AdventureWorks2014 recolecta los siguientes resultados:
El esquema, la tabla, el nombre, el porcentaje de fragmentación y el conteo de páginas son mostrados para cada índice en la base de datos. Los resultados son ordenados descendentemente por porcentaje de fragmentación, de modo que podamos aislar fácilmente índices con la fragmentación más alta.
Dependiendo del valor del porcentaje de fragmentación, la fragmentación puede ser reconocida como:
-
Alta fragmentación – los valores del porcentaje de fragmentación están encima de 30%. Los índices altamente fragmentados usualmente requieren la operación de reconstrucción.
-
Fragmentación media – para valores entre 10% y 30%. El mejor método para corregir la fragmentación media es usar la operación de reorganización.
-
Baja fragmentación – para los valores debajo de 10%. Los índices con baja fragmentación no requieren desfragmentación, dado que tienen mínimo impacto en el desempeño del servidor.
Tan pronto como el análisis está completo, podemos escribir el script de desfragmentación.
Escribiendo un script de desfragmentación
Para escribir un script personalizado, dedica qué índices desea incluir, dependiendo de los resultados de la consulta previa. Generalmente, los índices con niveles de fragmentación entre 10% y 30% necesitan ser reorganizados, mientras que aquellos con alta fragmentación necesitan ser reconstruidos. Otro factor importante cuando se elije qué índices incluir en el script, es el tamaño del índice. Los índices pequeños pueden ser incluidos en el scripts, pero desfragmentarlos no afecta el desempeño del servidor significativamente. En general, los índices más pequeños que 1000 páginas son raramente incluidos en los trabajos de desfragmentación.
Para reorganizar todos los índices en una tabla o sólo un índice específico, use las siguientes sentencias:
--Script 2: Reorganize script --2.1 Reorganize single index ALTER INDEX Index_name ON Table_name REORGANIZE ; --2.2 Reorganize all indexes in the table ALTER INDEX ALL ON Table_name REORGANIZE ;
El script para reconstruir tiene la misma sintaxis, pero usa la sentencia REBUILD:
--Script 3: Rebuild script --2.1 Rebuild single index ALTER INDEX Index_name ON Table_name REBUILD ; --2.2 Rebuild all indexes in the table ALTER INDEX ALL ON Table_name REBUILD ;
Escribir sentencias para reorganizar y reconstruir para cada índice, especialmente para bases de datos grandes, puede ser un trabajo pesado. Por lo tanto, decidimos usar un script dinámico que automáticamente revisa la fragmentación del índice y el tamaño de página del índice, y aplica las operaciones de reorganizar o reconstruir dependiendo de los resultados.
Para usar el script efectivamente, es necesario establecer unas pocas variables de umbral primeramente:
-
@reorg_frag_thresh – Umbral para reorganizar un índice en %. El valor sugerido para la variable es 10 (todos los índices con fragmentación entre 10% y 30% serán reorganizados).
-
@rebuild_frag_thresh – Umbral para reconstruir un índice en %. El valor sugerido para la variable es 30 (todos los índices con fragmentación de 30% y superior serán reconstruidos).
-
@fill_factor – Especifica el valor del factor de llenado para las operaciones de reconstrucción. El valor por defecto es 0 (factor de llenado al 100%). Es altamente recomendado no cambiar este valor, dado que puede resultar en el crecimiento de índices de reconstrucción si el valor está entre 1 y 99.
-
@page_count_thresh – Umbral de conteo de páginas. Todos los índices igual o más grandes que el número establecido de páginas serán procesados.
-- Script 4: Automatically analyze and defragment indexes -- Set variables -- ********************************************************************************************* SET NOCOUNT ON DECLARE @reorg_frag_thresh float SET @reorg_frag_thresh = 10.0 DECLARE @rebuild_frag_thresh float SET @rebuild_frag_thresh = 30.0 DECLARE @fill_factor tinyint SET @fill_factor = 0 DECLARE @report_only bit SET @report_only = 0 DECLARE @page_count_thresh smallint SET @page_count_thresh = 1 -- ********************************************************************************************* DECLARE @objectid int DECLARE @indexid int DECLARE @partitioncount bigint DECLARE @schemaname nvarchar(130) DECLARE @objectname nvarchar(130) DECLARE @indexname nvarchar(130) DECLARE @partitionnum bigint DECLARE @partitions bigint DECLARE @frag float DECLARE @page_count int DECLARE @command nvarchar(4000) DECLARE @intentions nvarchar(4000) DECLARE @table_var TABLE( objectid int, indexid int, partitionnum int, frag float, page_count int ) INSERT INTO @table_var SELECT [object_id] AS objectid, [index_id] AS indexid, [partition_number] AS partitionnum, [avg_fragmentation_in_percent] AS frag, [page_count] AS page_count FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') WHERE [avg_fragmentation_in_percent] > @reorg_frag_thresh AND page_count > @page_count_thresh AND index_id > 0 DECLARE partitions CURSOR FOR SELECT * FROM @table_var OPEN partitions WHILE (1=1) BEGIN FETCH NEXT FROM partitions INTO @objectid, @indexid, @partitionnum, @frag, @page_count IF @@FETCH_STATUS < 0 BREAK SELECT @objectname = QUOTENAME(o.[name]), @schemaname = QUOTENAME(s.[name]) FROM sys.objects AS o WITH (NOLOCK) JOIN sys.schemas AS s WITH (NOLOCK) ON s.[schema_id] = o.[schema_id] WHERE o.[object_id] = @objectid SELECT @indexname = QUOTENAME([name]) FROM sys.indexes WITH (NOLOCK) WHERE [object_id] = @objectid AND [index_id] = @indexid SELECT @partitioncount = count (*) FROM sys.partitions WITH (NOLOCK) WHERE [object_id] = @objectid AND [index_id] = @indexid SET @intentions = @schemaname + N'.' + @objectname + N'.' + @indexname + N':' + CHAR(13) + CHAR(10) SET @intentions = REPLACE(SPACE(LEN(@intentions)), ' ', '=') + CHAR(13) + CHAR(10) + @intentions SET @intentions = @intentions + N' FRAGMENTATION: ' + CAST(@frag AS nvarchar) + N'%' + CHAR(13) + CHAR(10) + N' PAGE COUNT: ' + CAST(@page_count AS nvarchar) + CHAR(13) + CHAR(10) IF @frag < @rebuild_frag_thresh BEGIN SET @intentions = @intentions + N' OPERATION: REORGANIZE' + CHAR(13) + CHAR(10) SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE; ' + N' UPDATE STATISTICS ' + @schemaname + N'.' + @objectname + N' ' + @indexname + ';' END IF @frag >= @rebuild_frag_thresh BEGIN SET @intentions = @intentions + N' OPERATION: REBUILD' + CHAR(13) + CHAR(10) SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD' END IF @partitioncount > 1 BEGIN SET @intentions = @intentions + N' PARTITION: ' + CAST(@partitionnum AS nvarchar(10)) + CHAR(13) + CHAR(10) SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10)) END IF @frag >= @rebuild_frag_thresh AND @fill_factor > 0 AND @fill_factor < 100 BEGIN SET @intentions = @intentions + N' FILL FACTOR: ' + CAST(@fill_factor AS nvarchar) + CHAR(13) + CHAR(10) SET @command = @command + N' WITH (FILLFACTOR = ' + CAST(@fill_factor AS nvarchar) + ')' END IF @report_only = 0 BEGIN SET @intentions = @intentions + N' EXECUTING: ' + @command PRINT @intentions EXEC (@command) END ELSE BEGIN PRINT @intentions END PRINT @command END CLOSE partitions DEALLOCATE partitions GO
Establecer políticas de desfragmentación con un trabajo de SQL Server Agent
Antes de comenzar con la configuración del trabajo, asegúrese de que SQL Server Agent esté instalado y corriendo. Para hacer esto, abra SQL Server Management Studio y encuentre SQL Server Agent al fondo de Object Explorer. Haga clic derecho en el agente y clic en el botón Start en el menú contextual. En el caso de que el agente ya esté corriendo, salte este paso.
Para crear un trabajo de SQL Server Agent que desfragmente índices especificados automáticamente, realice los siguientes pasos:
-
Expanda SQL Server Agent en Object explorer, haga clic derecho en Jobs y seleccione New Job…
-
En la pestaña General especifique el nombre y la descripción para el trabajo. Asegúrese de seleccionar la casilla Enabled . Proceda a la pestaña Steps .
-
Hacer clic en el botón New… en la pestaña Steps abre el formulario para la configuración del primer paso del trabajo. Provea cualquier nombre para el paso y deje todos los otros valores por defecto. En la ventana comando, pegue el script creado en el capítulo previo y haga clic en OK.
-
En la pestaña Schedules , en la ventana New job haga clic en el botón New para crear el programa para el trabajo. Establezca el tipo de programa, la frecuencia y la frecuencia diaria. Ya que las sentencias REBUILD bloquean las tablas durante el proceso de desfragmentación, es mejor establecer el programa a un momento cuando los servidores experimente la menor cantidad de tráfico. En este ejemplo, el programa está establecido para correr cada día a las 2:00 AM. Haga clic en OK para grabar el programa.
-
Si es necesario, establezca las Alerts y Notifications en las pestañas respectivas. En la pestañaTargets , especifique los objetivos para el trabajo. Para poder apuntar a múltiples servidores, es necesario crear ya sea un Servidor de administración central y un Grupo de Servidores Central Management Server and Server groups o un ambiente Multiservidor Multiserver environment. Haga clic en OK para finalizar la configuración del trabajo.
-
Para correr el trabajo seleccionado inmediatamente, expanda SQL Server Agent y Jobs en Object Explorer, haga clic derecho en el trabajo creado y seleccione Start Job at Step. Dado que su trabajo sólo tiene un paso, este empezará a ejecutarse automáticamente.
Establezca una política de desfragmentación con planes de mantenimiento
Para crear y correr políticas de desfragmentación con planes de mantenimiento, es necesario realizar los siguientes pasos en SQL Server Management Studio:
-
Expanda el nodo Management en Object Explorer, haga clic derecho en Maintenance Plans, y seleccione New Maintenance Plan… en el menú contextual. Especifique el nombre para el plan de mantenimiento y haga clic en OK.
-
Haga doble clic en Subplan_1.
-
En Subplan Properties, establezca el nombre y la descripción para el subplan y haga clic en el ícono de calendario.
-
Establezca el programa para el subplan. Cuando termine, haga clic en OK en las ventanas New Job Schedule y Subplan Properties.
-
Arrastre Rebuild Index Task y Reorganize Index Task desde Toolbox para limpiar el área en Defragmentation plan design. Si no hay una ventana Toolbox visible en la pantalla, enciéndala en la pestaña View de SSMS, o simplemente presione CTRL + ALT + X para activarla. Asegúrese de conectarse a la flecha verde desde Reorganize Index task con la ventana Rebuild Index Task.
-
Haga doble clic en Reorganize Index Task.
-
En la ventana abierta, seleccione la base de datos para la tarea desde el menú desplegableDatabase(s)
-
Desde el menú desplegable Object seleccione la opción Table. Si múltiples bases de datos fueron seleccionadas en el paso previo, esta opción estará deshabilitada y el trabajo reorganizará todos los índices en las bases de datos seleccionadas. Todas las tablas para la base de datos especificada están listados en el menú desplegable Selection . Vea los resultados del análisis de fragmentación de índice y seleccione las tablas que contienen índices con niveles de fragmentación que varían desde 10% a 30%. Haga clic en OK para grabar los cambios para Reorganize Index Task.
-
Haga doble clic en Rebuild Index Task. Como en los pasos 7 y 8, seleccione la base de datos y las tablas para añadir a la tarea. No hay necesidad de cambiar ningún ajuste en Free space options y Advanced options.
-
Haga clic derecho en la cabecera de Defragmentation plan design y elija Save Selected Items
-
El plan de mantenimiento está listo ahora, y correrá de acuerdo al programa establecido. Pero, si es necesario, puede correr inmediatamente. Para correr el plan creado inmediatamente, expanda los nodos Management y Maintenance Plans en Object Explorer. Haga clic derecho en el plan de mantenimiento creado y seleccione Execute
-
Tan pronto como el plan es ejecutado, un mensaje de éxito es mostrado.
Establecer políticas de desfragmentación en SQL Server con ApexSQL Defrag
Establecer políticas de desfragmentación con ApexSQL Defrag es fácil y sencillo. No hay necesidad de correr un análisis separado de fragmentación de índice, de usar consultas complejas o de memorizar qué índices necesitan ser desfragmentados. Las políticas de ApexSQL Defrag analizan todos los objetos seleccionados primero (bases de datos, tablas o índices individuales). Dependiendo de los resultados y umbrales establecidos, ApexSQL Defrag corre las operaciones de reorganizar o reconstruir automáticamente en los objetos seleccionados. Además, todas las políticas creadas pueden ser habilitadas o deshabilitadas en cualquier momento.
Para crear una política en ApexSQL Defrag, realice los siguientes pasos:
-
Para poder administrar un servidor con ApexSQL Defrag, añádalo a su lista de servidores. Abra ApexSQL Defrag, vaya a la pestaña Home y haga clic en el botón Add en el grupo Servers group. En la ventana Connection seleccione un servidor desde el menú desplegable. Especifique el tipo de autenticación, el nombre de usuario y la contraseña para el servidor seleccionado. El servidor aparecerá en la lista de servidores si se proveyeron credenciales válidas.
-
Para crear una nueva política, haga clic en el botón Policies encima de la barra de tareas, y seleccione Create
-
Establezca el nombre, la descripción y el programa para la nueva política.
-
En la caja Targets haga clic en el botón navegar (…). Seleccione los objetos que necesitan ser incluidos en la política. No hay necesidad de preocuparse acerca de la fragmentación actual del objeto seleccionado, ya que todos los objetos seleccionados son analizados automáticamente en cada corrida de la nueva política. Haga clic en OK para confirmar la selección.
-
Haga clic en la pestaña Thresholds . Los umbrales de la fragmentación del índice para las operaciones de reorganizar y reconstruir pueden ser establecidos manualmente en los dos deslizadores. El valor por defecto para reorganizar está entre 10% y 30%. Todos los índices que tienen un valor de fragmentación arriba de 30% serán reconstruidos por defecto.
-
El resultado final del análisis de fragmentación del índice depende del modo de escaneo seleccionado. Escoja entre los modos de escaneo limitado, de muestra y detallado.
-
Modo limitado – este es el modo más rápido que escanea el menor número de páginas. En el modo limitado, sólo las páginas encima del nivel más bajo del índice son escaneadas.
-
Modo de muestra – Sólo 1% de todas la páginas en un índice o una pila son escaneadas.
-
Modo detallado – Todas las páginas son escaneadas e incluidas en las estadísticas. Es el modo más lento y toma una gran cantidad de recursos cuando se compara con otros modos, pero retorna las estadísticas más precisas.
-
-
En Resources threshold, establezca los umbrales de la carga de la CPU o el uso de la memoria. La política parará automáticamente si cualquiera de los valores umbrales son alcanzados.
-
Si es necesario, establezca la notificación de correo electrónico en la pestaña Notification . Elija recibir notificaciones acerca de fallos de trabajos, éxitos de trabajos, o ambos. Para añadir receptores a la lista, haga clic en el botón Add y escriba la dirección de correo electrónico. Cuando termine, haga clic en OK para grabar los cambios.
La política está ahora disponible en la lista de políticas. Correrá automáticamente, basada en el programa establecido en el paso 3. Hay muchas operaciones en las políticas creadas que están disponibles en ApexSQL Defrag:
-
Si la política necesita ser corrida ya mismo, haga clic derecho en la política en la lista y seleccione Run from the context menu. The policy will execute immediately. The result of the last run is available as soon as policy completes.
-
La política seleccionada puede ser también habilitada o deshabilitada desde el menú contextual. Una política habilitada corre dependiendo de un programa establecido. Una política deshabilitada no se ejecutará hasta que sea habilitada de nuevo.
-
Si cualquier parámetro necesita ser cambiado para una política, es mejor usar el comando Edit desde el menú contextual.
-
Finalmente, si la política ya no es necesaria, puede ser eliminada ya sea usando el comando desde el menú contextual o seleccionándola y haciendo clic en el botón Delete en la cinta.
Related links:
- sys.dm_db_index_physical_stats (Transact-SQL)
- Reorganize and Rebuild Indexes
- What is causing database slowdowns?
diciembre 8, 2017