¿Por qué mi base de datos sigue fragmentada después de reconstruir y volver a indexar todo?

41

Tengo una base de datos que intenté desfragmentar todas las tablas a la vez ejecutando este T-SQL:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

Y luego copiar y pegar el resultado en una nueva ventana de consulta y ejecutarlo. No obtuve errores, pero todavía tengo fragmentación. Intenté ejecutar ambos comandos por separado también y todavía tengo fragmentación. Nota:REORGANIZE Aaron me ha informado que no es necesario, y sé que podría usar sql dinámico para automatizar esto.

Ejecuté esto para determinar que todavía tengo fragmentación:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

Y obtuve:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

Sé que me falta algo realmente básico, pero no sé qué.

Justin Dearing
fuente
¿Qué errores obtuviste? ¿También hay una razón por la que tiene que reorganizar y reconstruir lo mismo?
Shawn Melton
Shawn, pido disculpas por mi falta de una palabra. Tengo no hay errores. En cuanto a por qué ejecuté ambos comandos, lo hice después de probar cada comando individualmente. Actualicé mis preguntas.
Justin Dearing

Respuestas:

38

Las mesas son pequeñas. Los recuentos de páginas en sus tablas son:

11, 8, 6, 5, 13, 8, 10

Ocupan 480kb en total. Literalmente, no hay nada que desfragmentar.

Editar: esto garantiza un poco más de explicación.

Por lo general, a una nueva tabla o índice se le asignan las primeras 8 páginas desde una extensión mixta, en lugar de uniforme. Por lo tanto, es posible que cada una de las primeras 8 páginas se asigne desde diferentes extensiones mixtas. Por lo tanto, una tabla o índice que consume 8 páginas podría tener 8 fragmentos, 1 en cada uno de 8 extensiones mixtas diferentes.

Los scripts de desfragmentación más utilizados (un par de ejemplos vinculados a continuación) tienden a excluir tablas pequeñas debido a esto. IIRC, <500 páginas están en una o en ambas. En estos tamaños, la desfragmentación tiene muy pocos beneficios y las cifras de fragmentación están potencialmente sesgadas por las asignaciones de extensión mixta.

Mark Storey-Smith
fuente
Ok, eso es satisfactorio a menos que alguien más tenga una mejor respuesta, marcaré la suya como correcta.
Justin Dearing
3
+1 De acuerdo con Mark. Preocúpese por la fragmentación cuando realmente tenga algunos datos. :-)
Aaron Bertrand
Comprendo completamente lo que estás diciendo. Pero solo por pura curiosidad, ¿esto se debe a que el motor db simplemente no puede desfragmentar tan pocas páginas? Quiero decir, debe haber una razón para esto.
Thomas Stringer
3
No es que no pueda, pero ¿por qué molestaría? Hacerlo tendrá poco o ningún impacto en la E / S, especialmente porque las tablas de este tamaño están casi garantizadas de todos modos en la memoria.
Aaron Bertrand
1
Sólo. Parece extraño, eso es todo. Digamos que estoy escribiendo una aplicación para verificar e informar sobre la fragmentación del índice, tendría que agregar una lógica adicional no solo para probar el porcentaje de fragmentos, sino también la cantidad de páginas para que no haya falsas alarmas.
Thomas Stringer
19

Cita de " Mejores prácticas de desfragmentación de índice de Microsoft SQL Server 2000 ":

"La fragmentación afecta la E / S del disco. Por lo tanto, concéntrese en los índices más grandes porque es menos probable que SQL Server almacene en caché sus páginas. Utilice el recuento de páginas informado por DBCC SHOWCONTIG para tener una idea del tamaño de los índices (cada página es 8 KB de tamaño). En general, no debe preocuparse por los niveles de fragmentación de los índices con menos de 1,000 páginas. En las pruebas, los índices que contienen más de 10,000 páginas obtuvieron ganancias de rendimiento, con las mayores ganancias en los índices con significativamente más páginas (mayor de 50,000 páginas) ".

Entonces, este tipo de respuesta a su pregunta y respalda las respuestas de Mark y Aaron.

Puede encontrar buena información sobre la fragmentación del índice en los siguientes artículos de Brent Ozar:

Además ... se puede encontrar un océano de gran información sobre los índices en general (también sobre cuestiones de fragmentación) en el blog de Kimberly Tripp .

Mariana
fuente
12

Esto no pretende responder a su pregunta, pero nunca cabe en un comentario. Puede crear este script dinámicamente sin tener que copiar y pegar el resultado en otra ventana. Teniendo en cuenta que no hay absolutamente ninguna razón para REORGANIZEy luego REBUILD:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;
Aaron Bertrand
fuente
Aaron, gracias por señalar el sql dinámico, soy muy consciente del sql dinámico, no iba a automatizar la solución hasta que funcionara. Sin embargo, otros que lean esto probablemente deberían estar conscientes.
Justin Dearing