¿Cómo reducir la fragmentación HEAP en SQL Server?

10

Hace poco descubrí que una tabla de montón tenía más del 70% de fragmentación. Entonces decidí hacer un

ALTER TABLE dbo.myTable REBUILD

Curiosamente, después tuve un 20% de fragmentación. No había escrito en esa mesa desde entonces. Así que decidí hacer la reconstrucción una vez más.

Después de la segunda vez, la mesa tiene una fragmentación del 50%, ¡así que aún más! Realmente no entiendo cómo puede suceder esto ...

tuxmania
fuente
¿Qué quieres decir cuando dices fragmentación lógica? Es la fragmentación en términos de uso de páginas de datos. Sé que no hay orden, pero los datos no ordenados no están fragmentados per se. La fragmentación en este caso significa el uso eficiente de las páginas de datos.
tuxmania
2
Supongo que deberíamos preguntar, ¿qué tan grande es la mesa? En filas y páginas.
Cody Konior

Respuestas:

17

¿Qué significa la fragmentación en un montón?

El valor de fragmentación en el montón que obtiene de la columna avg_fragmentation_in_percental consultar sys.dm_db_index_physical_statsDMV indica que

Fragmentación lógica para índices, o fragmentación de extensión para montones en la unidad de asignación IN_ROW_DATA.

Además, el mismo BOL dice que

Este es el porcentaje de extensiones fuera de orden en las páginas de hoja de un montón. Una extensión fuera de orden es aquella en la que la extensión que contiene la página actual para un montón no es físicamente la siguiente extensión después de la extensión que contiene la página anterior.

Entonces puede ver que no es el espacio libre presente en las páginas asignadas a Heap sino la secuencia variable de páginas lo que crea la fragmentación.

Esto se puede demostrar mediante una pequeña prueba. Creemos una tabla de montón e inserte algunos registros en ella y luego verifiquemos la fragmentación.

create table dbo.HeapTest
(
Id INT not NULL Default (1),
Col1   char(5000) Not null Default ('Heaps Are Cool')
)

SET NOCOUNT ON

Insert into dbo.Heaptest default values
go 50

select index_type_desc,avg_fragmentation_in_percent,fragment_count,
avg_page_space_used_in_percent,record_count
from sys.dm_db_index_physical_stats(db_id(),object_id('dbo.HeapTest','U'),0,default,'detailed')

Por lo tanto, la tabla del montón se crea con 50 registros. A continuación se muestra cómo se ve la fragmentación después de la consulta DMV sys.dm_db_index_physical stats

ingrese la descripción de la imagen aquí

Puede ver avg_fragmentation_in_percentque el valor de la columna es 33%. Ahora veamos cómo están organizadas las páginas. Esto se puede hacer mediante la consulta no documentada%%lockres%% . La consulta sería

SELECT  %%lockres%%, * FROM dbo.HeapTest;

Y a continuación se muestra cómo se ve la salida. Adjuntando solo una parte relevante del mismo. La consulta produjo 50 filas ya que insertamos 50 filas en nuestra tabla dbo.HeapTest.

ingrese la descripción de la imagen aquí

Lo que dice es que la primera página tiene ID, 197la página siguiente tiene ID. Las 242páginas siguientes tienen ID continua hasta que alcanzamos la ID de la página 264porque después de eso obtenemos la ID de la página 280. Entonces, este salto en los números de ID de página es lo que realmente causa la fragmentación.

Ahora no sea que reconstruya el montón y ejecute el comando nuevamente para ver la fragmentación y cómo se organizan las páginas. Obtenemos fragmentación como

ingrese la descripción de la imagen aquí

Puedes ver que la fragmentación es ahora 14%.

Veamos los números de página asignados

ingrese la descripción de la imagen aquí

Solo tenemos un salto de salto; todas las páginas tienen asignada la ID de página en serie. Dado que solo un salto la fragmentación disminuyó considerablemente.

Reconstruí el montón nuevamente y ahora, cuando verifiqué la fragmentación, desapareció por completo. Y la asignación de ID de página es como

ingrese la descripción de la imagen aquí

Por qué aumentó la fragmentación

Ahora, con respecto a lo que podría haber causado el aumento de la fragmentación, podemos corroborarlo al hecho de que cuando las páginas se asignaban al montón, no serían continuas, como se vio anteriormente, lo que causó que el valor de la fragmentación aumentara fue el salto en la ID de PÁGINA asignada a las páginas.

En la parte posterior de la cabeza, también debe tener en cuenta que la palabra fragmentación para HEAP no tiene ningún significado, ¿cómo definiría la fragmentación para un montón de páginas no ordenadas?

Realmente preocupado por la fragmentación

Si realmente enfrenta un escenario en el que la tabla de montón está fragmentada y ralentiza las consultas, sería mejor crear un índice agrupado en la tabla que reconstruirlo. La razón es que cuando reconstruye el montón todos los índices subyacentes no agrupados también se reconstruyen, lo que hace que el proceso de reconstrucción tarde mucho más tiempo, utilizando muchos recursos y un registro de transacciones hinchado. En un sistema de producción, uno siempre trataría de evitar esto. Paul cubrió esto en su Sección de Mitos sobre el montón .

PD: No utilices comandos no documentados en el sistema de producción. Esto fue solo para demostración.

Shanky
fuente
Gracias por tu análisis detallado. Me enfrento a grandes tablas de montón porque algunos entusiastas de la bóveda de datos piensan que es mucho mejor que usar índices agrupados, pero luego usan muchas restricciones de verificación e índices no agrupados en esos montones, por lo que realmente no veo el beneficio de los montones en esta situación. Sin embargo, dado que solo soy el estúpido desarrollador, tengo que lidiar con esto. Gracias de nuevo por la información :)
tuxmania
¿Cómo se ejecuta select index_type_desc, avg_fragmentation_in_percent, fragment_count, avg_page_space_used_in_percent, record_count from sys.dm_db_index_physical_stats (db_id (), object_id ('dbo.HeapTest', 'U') ',' solo ', resultado predeterminado, solo el, el resultado predeterminado una mesa ? regresa en todos los índices en todas las tablas para mí, incluso si especifico correctamente el nombre de mi tabla en 'object_id'
Mickael
@Mickael He usado la función db_id () que tomaría la base de datos actual y he dado específicamente el nombre del objeto para que siempre busque en la base de datos actual y busque Heaptesty dé el resultado. Estoy seguro de que te habrás perdido algo. Solo asegúrese de que el nivel de compatibilidad no sea 80 en ese caso, la función db_id no funcionará
Shanky
@Shanky, ¿por qué no recomienda utilizar la consulta no documentada %% lockres %% en la producción? ¿Podría explicarlo en detalle?
Ralph
@ user1624552 Simplemente porque no está documentado, significa que MS tampoco mantiene actualizada la documentación al respecto. ¿Cuáles son sus efectos posteriores? ¿Cómo funciona? No está documentado en ninguna parte, por eso se le pregunta. Por ejemplo, hay un comando fn_dump_dblog () que crea un planificador oculto y eso no es bueno. Este comando tampoco es compatible. Puede usarlo, pero el riesgo recae en usted.
Shanky