reconstruir en índice agrupado, ¿por qué se reduce el tamaño del datasize?

10

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
Daniel Björk
fuente
¿Está determinando el tamaño de los datos a partir del tamaño del archivo?
JNK
Tamaño de datos me refiero a la columna de "datos" de DBCC sp_spaceused
Daniel Björk
Esa sería la columna de "datos" de EXEC sp_spaceused.
RLF
1
¿Se olvidó todo el mundo de que OP está usando la compresión de página = habilitada en su script de reconstrucción y supongo que no era antes? Daniel puedes confirmar?
Shanky
1
@Shanky: Parece que esa ALTER INDEXdeclaració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?)
David Spillett

Respuestas:

16

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:

Start with one empty page: 
        [__|__|__|__]
Add the first item in index order:
        [00|__|__|__]
Add the next three
        [00|02|04|06]
Adding the next will result in a new page:
        [00|02|04|06] [08|__|__|__]
And so on...
        [00|02|04|06] [08|10|12|14] [16|18|__|__]

Ahora, para agregar filas fuera de orden de índice (es por eso que usé números pares solo arriba): Agregar 11significarí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í:

[00|02|04|06] [08|10|11|__] [12|14|__|__] [16|18|__|__]

A partir de aquí, agregar 13y 17no resultará en una división ya que actualmente hay espacio en las páginas relevantes:

[00|02|04|06] [08|10|11|__] [12|13|14|__] [16|17|18|__]

pero agregar 03 hará lo siguiente:

[00|02|03|__] [04|06|__|__] [08|10|11|__] [12|13|14|__] [16|17|18|__]

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:

[00|02|03|04] [06|08|10|11] [12|13|14|16] [17|18|__|__]

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 FILLFACTORopció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 FILLFACTORlo 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 INDEXdeclaració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.

David Spillett
fuente
2
+1 Si el factor de relleno de la página es inferior al 100%, por ejemplo, si el factor de relleno de la página era del 50%, el índice agrupado recientemente reconstruido (la tabla ) sería dos veces mayor que si se reconstruyera con un factor de relleno del 100%.
Max Vernon
6

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_spaceusedno 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.

Aaron Bertrand
fuente
5

El sp_spaceusedprocedimiento 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.

RLF
fuente