Cuando realizamos una reconstrucción en un índice agrupado en una tabla que tiene aproximadamente 15 gb de datos y el tamaño de datos se redujo a 5 gb, ¿cómo puede ser esto? ¿Qué tipo de "datos" se eliminan?
Tamaño de datos me refiero a la columna "datos" de DBCC sp_spaceused
Antes de reconstruir en el índice agrupado:
name rows reserved data index_size unused LEDGERJOURNALTRANS 43583730 39169656 KB 15857960 KB 22916496 KB 395200 KB
Después de reconstruir en el índice agrupado:
name rows reserved data index_size unused LEDGERJOURNALTRANS 43583730 29076736 KB 5867048 KB 22880144 KB 329544 KB
TSQL para reconstrucción:
USE [DAX5TEST]
GO
ALTER INDEX [I_212RECID] ON [dbo].[LEDGERJOURNALTRANS] REBUILD PARTITION = ALL WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, ONLINE = ON, SORT_IN_TEMPDB = OFF, DATA_COMPRESSION = PAGE, FILLFACTOR = 85 )
GO
sql-server
clustered-index
Daniel Björk
fuente
fuente
EXEC sp_spaceused
.ALTER INDEX
declaración fue generada por el código (ya que incluye un montón de opciones en su configuración predeterminada), por lo que sospecho que se creó a partir de las opciones existentes del índice. Pero tiene razón: si la compresión no estaba habilitada en el índice agrupado antes de que se ejecutara, eso definitivamente explicaría la mayor parte de la reducción en la huella de datos. (de nuevo: Daniel, ¿podrías confirmar de una forma u otra?)Respuestas:
Cuando una tabla tiene un índice agrupado, el índice son los datos de la tabla (de lo contrario, tiene una tabla de tipo de montón). Una reconstrucción del índice agrupado (cualquier índice de hecho, pero el espacio no se contará como "datos" para un índice no agrupado) dará como resultado que las páginas parcialmente utilizadas se fusionen en una forma más completa.
A medida que inserta datos en un índice (agrupado o no) en el orden del índice, las páginas de hojas se crean según sea necesario y solo tendrá una página parcial: la que está al final. A medida que ingresa datos fuera del orden del índice, se debe dividir una página para que los datos se ajusten en el lugar correcto: termina con dos páginas que están aproximadamente a la mitad y la nueva fila entra en una de ellas. Con el tiempo, esto puede suceder mucho, consumiendo una buena cantidad de espacio extra, aunque hasta cierto punto las futuras inserciones llenarán algunos de los vacíos. Las páginas que no son hojas también verán un efecto similar, pero las páginas de datos reales son mucho más significativas en tamaño de lo que lo son.
También elimina puede dar lugar a páginas parciales. Si elimina todas las filas de una página, se cuenta como "sin usar", pero si le quedan una o más filas de datos, todavía se cuenta como en uso. Incluso si solo hay una fila con 10 bytes en una página, esa página cuenta como 8192 bytes en el recuento de espacio utilizado. Nuevamente, las futuras inserciones podrían llenar parte del vacío.
Para las filas de longitud variable, las actualizaciones también pueden tener el mismo efecto: a medida que una fila se hace más pequeña, puede dejar espacio en su página que luego no es fácil de reutilizar, y si una fila en una página casi completa crece más, podría forzar una división de la página .
SQL Server no pasa tiempo tratando de normalizar los datos reorganizando cómo se usan las páginas, hasta que se le indique explícitamente, como su orden de reconstrucción de índice, ya que tales ejercicios de recolección de basura podrían ser una pesadilla de rendimiento.
Sospecho que esto es lo que está viendo, aunque diría que tener suficiente espacio asignado para ~ 2.7 veces la cantidad que los datos necesitan absolutamente es un caso particularmente malo. Puede implicar que tiene algo aleatorio como una de las claves significativas en el índice (una columna UUID tal vez), lo que significa que es poco probable que se agreguen nuevas filas en el orden del índice, y / o que haya ocurrido un número significativo de eliminaciones recientemente.
Ejemplo de división de página
Inserción en orden de índice con filas de longitud fija de las cuales cuatro caben en una página:
Ahora, para agregar filas fuera de orden de índice (es por eso que usé números pares solo arriba): Agregar
11
significaría extender esa segunda página (no es posible ya que son de tamaño fijo), moviendo todo lo anterior arriba de 11 (demasiado caro en un índice grande) o dividir la página así:A partir de aquí, agregar
13
y17
no resultará en una división ya que actualmente hay espacio en las páginas relevantes:pero agregar 03 hará lo siguiente:
Como puede ver, después de esas operaciones de inserción, actualmente tenemos 5 páginas de datos asignadas que podrían caber en un total de 20 filas, pero solo tenemos 14 filas allí ("desperdiciando" el 30% del espacio).
Una reconstrucción con opciones predeterminadas (ver más abajo sobre "factor de relleno") daría como resultado:
guardando una página en este simple ejemplo. Es fácil ver cómo las eliminaciones pueden tener un efecto similar al de las inserciones fuera de índice.
Mitigación
Si espera que los datos se presenten en un orden bastante aleatorio con respecto al orden del índice, puede usar la
FILLFACTOR
opción al crear o reconstruir un índice para indicarle a SQL Server que deje huecos artificialmente para rellenarlos más tarde, reduciendo las divisiones de página a largo plazo, pero tomando más espacio inicialmente. Por supuesto, equivocarse en este valor puede empeorar las cosas en lugar de mejorar la situación, así que maneje con cuidado.La división de páginas, particularmente en el índice agrupado, puede tener una implicación de rendimiento para las inserciones / actualizaciones, por
FILLFACTOR
lo que a veces se modifica por esa razón en lugar del problema del uso del espacio en las bases de datos que ven mucha actividad de escritura (pero para la mayoría de las aplicaciones, donde las lecturas superan a las escrituras en varios órdenes de magnitud, generalmente es mejor dejar el factor de relleno al 100%, excepto en casos específicos como donde tiene índices sobre columnas con contenido efectivamente aleatorio).Supongo que otros DB de gran nombre tienen una opción similar, si también necesita este nivel de control en ellos.
Actualizar
Con respecto a la
ALTER INDEX
declaración agregada a la pregunta después de que comencé a escribir lo anterior: supongo que las opciones son las mismas que cuando se creó el índice por primera vez (o se reconstruyó por última vez), pero si no, la opción de compresión podría ser muy significativa si se agregara esto tiempo alrededor. También en esa declaración, el factor de relleno se establece en 85%, no en 100%, por lo que cada página hoja estará vacía ~ 15% inmediatamente después de la reconstrucción.fuente
Cuando reconstruye un índice, literalmente coloca todos los datos en páginas nuevas. Lo que sospecho que sucedió es que eliminó muchos datos antes de la reconstrucción, por ejemplo, eliminó una columna, actualizó una columna de ancho variable para tener menos datos, cambió el tamaño de una columna de ancho fijo o eliminó muchas filas. Cualquiera de estas operaciones podría dejar mucho espacio vacío en las páginas, que no se recuperarían hasta la reconstrucción. La columna "datos"
sp_spaceused
no mide los datos reales, sino el número de páginas de 8K que se usan para almacenar los datos. Esas páginas ahora están más llenas debido a la reconstrucción, por lo que la misma cantidad de datos se ajusta en un número menor de páginas.fuente
El
sp_spaceused
procedimiento almacenado no examina el tamaño total de las filas de la base de datos. Informa el tamaño del espacio asignado para mantener esos datos en el tamaño acumulativo de las extensiones asignadas para los datos.Si hay espacio libre significativo disponible, como el de muchas filas eliminadas, una reconstrucción del índice agrupado compactaría el espacio en páginas y extensiones para ser más eficiente (es decir, más pequeño) por razones de rendimiento.
Por lo tanto, no se deben descartar datos, pero el proceso de reconstrucción hizo que ese espacio libre que estaba incrustado en las páginas de datos estuviera disponible nuevamente.
fuente