¿Cuáles son los escenarios de uso válidos para las tablas HEAP?


31

Actualmente estoy haciendo algunas importaciones de datos en un sistema heredado y descubrí que este sistema no usa un solo índice agrupado. Una búsqueda rápida en Google me presentó el concepto de tablas HEAP y ahora tengo curiosidad sobre en qué escenarios de uso se debería preferir una tabla HEAP a una tabla agrupada.

Hasta donde entendí, una tabla HEAP solo sería útil para las tablas de auditoría y / o donde las inserciones ocurren con mucha más frecuencia que las seleccionadas. Ahorraría espacio en disco y E / S de disco ya que no hay un índice agrupado para mantener y la fragmentación adicional no sería un problema debido a las lecturas muy raras.


1
¿Estás hablando de SQL Server?
a_horse_with_no_name

@a_horse_with_no_name sí, olvidé mencionar a ese sry
marc.d

Las tablas de montón son buenas para las tablas con millones de filas que son golpeadas fuertemente por los usuarios. La desventaja es que pueden ocupar mucho espacio porque los datos se almacenan físicamente sin clasificar. Además, confía en sus índices para que se sintonicen con sus consultas. He trabajado en lugares que no usaban índices agrupados en absoluto debido a problemas de rendimiento. Probablemente debido a malas elecciones de índices agrupados, pero si solo usa tablas de montón, no tiene que preocuparse por eso. Una mejor solución sería utilizar la edición empresarial del servidor sql y particionar horizontalmente la tabla grande. Pero si no tiene el ent


Respuestas:


22

Los únicos usos válidos son para

  • tablas de preparación utilizadas en los procesos de importación / exportación / ETL.
  • copia de seguridad ad-hoc, temporal y a corto plazo de tablas usando SELECT * INTO..

Las tablas de etapas suelen ser bastante planas y truncadas antes / después del uso.

Tenga en cuenta que un índice agrupado suele ser pequeño en comparación con el tamaño de los datos: los datos son el nivel más bajo de la estructura del índice.

Las tablas de montón también tienen problemas. Al menos estos:

Ver también


2
Normalmente usa montones para dos cosas separadas. Puesta en escena ETL y tablas de trabajo que uso para almacenar datos temporalmente cuando el conjunto es demasiado grande para que una tabla temporal funcione de manera efectiva. Todos los cuales se truncan en la próxima carga.
Zane

Buena pregunta por cierto.
Zane

1
Una pequeña modificación: si realiza una SELECCIONAR EN para crear una copia de seguridad rápida de una tabla pequeña antes de realizar un cambio, se creará un montón de forma predeterminada. Yo diría que es un uso válido, pero eso es solo una trampa. Quisiera deshacerme de ese montón tan pronto como supiera que mi trabajo estaba hecho.
Brent Ozar

@BrentOzar: De acuerdo, lo hago todo el tiempo yo mismo. El espíritu de mi respuesta es "tablas a largo plazo y persistentes", pero actualizaré
gbn

9

Consideraciones mayores

Veo una ventaja importante para los montones y otra para las tablas agrupadas, más una tercera consideración que puede ser de cualquier manera.

  • Un montón le ahorra una capa de indirección. Los índices contienen ID de fila, apuntando directamente (bueno, no realmente, pero lo más directamente posible) a una ubicación de disco. Por lo tanto, una búsqueda de índice contra un montón debería costar aproximadamente la mitad de una búsqueda de índice no agrupada contra una tabla agrupada.

  • Un índice agrupado se ordena, per se, gracias a un índice (casi) libre. Debido a que el índice de agrupación se refleja en el orden físico de los datos, ocupa relativamente poco espacio en la parte superior de los datos reales, que por supuesto tiene que almacenar de todos modos. Debido a que está físicamente ordenado, un escaneo de rango contra este índice puede buscar el punto de inicio y luego avanzar hasta el punto final de manera muy eficiente.

  • Los índices en los montones hacen referencia a los RID, que son de 64 bits. Como se mencionó, los índices no agrupados en una tabla agrupada hacen referencia a la clave de agrupación, que puede ser más pequeña (una de 32 bits INT), la misma (una de 64 bits BIGINT) o más grande (una de 48 bits DATETIME2()más una de 32 bits INT, o un GUID de 128 bits). Obviamente, una referencia más amplia genera índices más grandes y más caros.

Requerimientos de espacio

Con estas dos tablas:

CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)

CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)

... cada uno con 8,7 M de registros, el espacio requerido era de 150 MB para los datos de ambos; 120 MB para los índices de la tabla agrupada, 310 MB para los índices de la tabla no agrupada. Esto refleja que el índice agrupado es más angosto que un RID, y que el índice agrupado es principalmente un "regalo de promoción". Sin los índices únicos ID2, el espacio de índice requerido cae a 155 MB para la tabla no agrupada (la mitad, como era de esperar) pero solo 150 KB para la PK agrupada, casi nada.

Por lo tanto, un índice no agrupado de un campo de 32 bits en una tabla agrupada con un índice de 32 bits (total de 64 bits, nominalmente) tomó 120 MB, mientras que un índice de un campo de 32 bits en un montón de 64 bits RID (total de 96 bits, nominalmente) tomó 155 MB, un poco menos del aumento del 50% que uno esperaría ingenuamente pasar de claves de 64 bits a 96 bits, pero por supuesto hay una sobrecarga que reduce la diferencia efectiva de tamaño.

Completar las dos tablas y crear sus índices tomó la misma cantidad de tiempo para cada tabla. Al ejecutar pruebas simples que involucran escaneos o búsquedas, no encontré diferencias materiales de rendimiento entre las tablas, lo que coincide con el documento técnico de Microsoft que gbn ayudó de manera útil. Dicho documento muestra una diferencia significativa para el acceso altamente concurrente; No estoy seguro de por qué sucede eso, espero que alguien con más experiencia que yo con sistemas OLTP de alto volumen pueda decirnos.

Agregar ~ 40 bytes de datos aleatorios de longitud variable no cambió apreciablemente esta equivalencia. Reemplazar los INTs con UUID anchos tampoco (cada tabla se desaceleró aproximadamente en la misma medida). Su millaje puede variar, pero en la mayoría de los casos si un índice está disponible es más importante que de qué tipo.

Pedazos y pedazos

Hacer un escaneo de rango contra un índice no agrupado, ya sea porque la tabla es un montón o porque el índice no es el índice agrupado, implica escanear el índice y luego buscar en la tabla para cada golpe. Esto puede ser muy costoso, por lo que a veces es más barato escanear la tabla. Sin embargo, puede solucionar esto con un índice de cobertura. Esto se aplica tanto si ha agrupado su tabla como si no.

Como señaló @gbn, no hay una manera simple de compactar un montón. Sin embargo, si su tabla aumenta gradualmente con el tiempo, un caso muy común, habrá poco desperdicio ya que el espacio liberado por las eliminaciones se llenará con nuevos datos.

Varias de las discusiones del montón frente a la tabla agrupada que he visto hacen un curioso argumento de que un montón sin índices es inferior a una tabla agrupada ya que siempre requiere un escaneo de la tabla. Esto es ciertamente cierto, pero la comparación más significativa es "gran tabla agrupada bien indexada" versus "gran montón bien indexado". Si su tabla es muy pequeña o siempre va a hacer escaneos de tablas, entonces no importa mucho si la agrupa o no.

Debido a que cada índice en una tabla agrupada hace referencia al índice de agrupación, en realidad son todos índices de cobertura. Una consulta que hace referencia a una columna indexada y a la (s) columna (s) de agrupación puede realizar una exploración de índice sin ninguna búsqueda en la tabla. Esto generalmente no es valioso si su índice de agrupación es una clave sintética, pero si se trata de una clave comercial que necesitaría recuperar de todos modos, es una buena característica.

TL; DR

Soy un chico de almacenamiento de datos, no un experto en OLTP. Para las tablas de hechos, casi siempre utilizo un índice de agrupación en el campo que probablemente necesite escaneos de rango, generalmente un campo de fecha. Para las tablas de dimensiones, me agrupo en la PK, por lo que está clasificada previamente para combinar combinaciones con tablas de hechos.

Existen varias razones para usar índices de agrupamiento, pero si ninguna de esas razones se aplica, entonces la sobrecarga puede no valer la pena. Sospecho que hay un montón de "siempre lo hemos hecho de esta manera" y "es la mejor práctica" detrás de las personas que usan índices agrupados universalmente. Pruebe ambos con sus datos y su carga y vea qué funciona mejor.


5

Creo que decir "El único uso válido es para las tablas de preparación utilizadas en los procesos de importación / exportación / ETL" es un poco restrictivo por decir lo menos. Debe tomar el caso de uso esperado de un sistema determinado y luego elegir según los méritos de los montones o tablas organizadas de índice (lo sé, un término de Oracle pero lo describe muy bien).

Nuestro almacén carga aproximadamente 1.500 millones de filas al día y debe admitir escrituras y procesos altamente concurrentes, así como lecturas. El almacén relacional admite una base de datos OLAP y, por lo tanto, las lecturas tienden a ser principalmente escaneos de tablas. Los informes y las fuentes posteriores que se generan generalmente tampoco son lo suficientemente selectivos como para que cualquier índice sea útil. El sistema admite una ventana deslizante de datos y, por lo tanto, una vez que se carga una tabla, rara vez volvemos a escribir en ella y dada la implementación bastante pobre de particionamiento de tablas que requiere bloqueos Sch-M para divisiones, conmutadores y fusiones de particiones frente a bloqueos Sch-S para lecturas, etc. , el sistema tuvo que hacer uso de muchas tablas, aunque también tenemos algunas tablas particionadas. El uso de muchas tablas facilita la segmentación de los datos y los ciclos de limpieza al tiempo que reduce la contención.

Como tal, la sobrecarga agregada de una tabla organizada de índice (tabla agrupada) en algunas columnas arbitrarias frente a poder bcp en un montón, procesar las particiones OLAP, realizar algunas consultas de escaneo de tablas y luego 3 días más tarde, descartarlo significa que simplemente no vale la pena. Tenga en cuenta que, en nuestro caso, los datos regresan de un gran clúster de cuadrícula, por lo que tampoco hay que ordenarlos, por lo que insertarlos en una tabla con un índice agrupado podría introducir otros problemas, como "puntos calientes" y divisiones de página y similares.

Además, creo que el argumento sobre las páginas dispersas es un poco falso. Los índices agrupados también pueden tener sus páginas dispersas por todo el archivo. Es solo que después de volver a indexar (suponiendo más de 1000 páginas) esto puede ser mejor que un montón, pero luego también tuvo que volver a indexar.

También es posible ahorrar espacio usando columnas dispersas y compresión si eso es un problema. Es cierto que, en algunos casos, las selecciones en una tabla con un índice agrupado pueden ser más rápidas, pero debe sopesarlo con los recursos necesarios para cargarlo y mantenerlo.

[Editar] Probablemente debería dejar en claro que solo nuestras tablas de hechos no particionadas son montones. Las tablas particionadas y las tablas de dimensiones tienen índices agrupados para admitir búsquedas eficientes, etc. [Editar2] Se corrigieron 2.500 a 1.500 millones. Pero esos dos números están uno al lado del otro. Supongo que sucede al escribir respuestas en un teléfono ...

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.