Agrupados frente a no agrupados

98

Mi conocimiento de nivel inferior de SQL (Server 2008) es limitado y ahora está siendo cuestionado por nuestros DBA. Déjame explicarte (he mencionado declaraciones obvias con la esperanza de estar en lo cierto, pero si ves algo mal, dímelo) el escenario:

Tenemos una mesa que contiene 'Órdenes judiciales' para las personas. Cuando creé la tabla, (Nombre: CourtOrder), la creé como:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Luego apliqué un índice no agrupado a la clave principal (para mayor eficiencia). Mi razón es que es un campo único (clave primaria) y debe indexarse, principalmente con fines de selección, como solemosSelect from table where primary key = ...

Luego apliqué un índice CLUSTER en PersonId. El motivo era agrupar los pedidos de una persona en particular físicamente, ya que la gran mayoría del trabajo es recibir pedidos de una persona. Entonces,select from mytable where personId = ...

Me han detenido en esto ahora. Me han dicho que deberíamos poner el índice agrupado en la clave principal y el índice normal en personId. Eso me parece muy extraño. En primer lugar, ¿por qué pondría un índice agrupado en una columna única? ¿Qué es la agrupación? ¿Seguramente eso es un desperdicio del índice agrupado? Habría creído que se usaría un índice normal en una columna única. Además, agrupar el índice significaría que no podemos agrupar una columna diferente (una por tabla, ¿verdad?).

El motivo por el que me han dicho que he cometido un error es que creen que poner un índice agrupado en PersonId haría que las inserciones fueran lentas. Para el aumento del 5% en la velocidad de una selección, obtendríamos una degradación del 95% en la velocidad en inserciones y actualizaciones. ¿Es eso correcto y válido?

Dicen que debido a que agrupamos el personId, SQL Server tiene que reorganizar los datos cada vez que insertamos o hacemos un cambio en el PersonId.

Entonces, he preguntado, ¿por qué SQL tendría el concepto de ÍNDICE CLÚSTER, si es tan lento? ¿Es tan lento como dicen? ¿Cómo debería haber configurado mis índices para lograr un rendimiento óptimo? Pensé que SELECT se usa más que INSERT ... pero dicen que estamos teniendo problemas de bloqueo en INSERTS ...

Espero que alguien pueda ayudarme.

Craig
fuente

Respuestas:

117

La distinción entre un índice agrupado y no agrupado es que el índice agrupado determina el orden físico de las filas en la base de datos . En otras palabras, aplicar el índice agrupado a PersonIdsignifica que las filas se ordenarán físicamente por PersonIden la tabla, lo que permitirá que una búsqueda de índice en esto vaya directamente a la fila (en lugar de un índice no agrupado, que lo dirigirá a la fila ubicación, agregando un paso adicional).

Dicho esto, es inusual que la clave principal no sea el índice agrupado, pero no es inaudito. El problema con su escenario es en realidad lo contrario de lo que está asumiendo: desea valores únicos en un índice agrupado, no duplicados. Debido a que el índice agrupado determina el orden físico de la fila, si el índice está en una columna no única, entonces el servidor tiene que agregar un valor de fondo a las filas que tienen un valor de clave duplicado (en su caso, cualquier fila con el mismo PersonId) para que el valor combinado (clave + valor de fondo) sea único.

Lo único que sugeriría es no usar una CourtOrderIdcolumna de clave sustituta (su ) como clave principal, sino usar una clave primaria compuesta de la PersonIdy alguna otra columna o conjunto de columnas de identificación única. Sin embargo, si eso no es posible (o no es práctico), active el índice agrupado CourtOrderId.

Adam Robinson
fuente
Gracias Adam. Entonces, ¿cuándo sería útil un índice agrupado? Pensé que el beneficio del índice agrupado era agrupar los datos, para los momentos en que, por ejemplo, la mayoría de las consultas están en un PersonID ... para que los datos se agrupen.
Craig
3
Se no ordenadas físicamente por PersonId. Está ordenado lógicamente por PersonId, cualquier discrepancia entre el orden lógico y físico es el grado de fragmentación lógica.
Martin Smith
1
@cdotlister El beneficio de un índice es ordenar los datos, no agruparlos (lo que implicaba datos duplicados dentro del índice). Si bien la distinción puede parecer semántica, en el caso de índices agrupados no lo es. Si es posible, el índice agrupado debe estar en algo que identifique de forma única la fila y (idealmente) también sea la columna o el conjunto de columnas consultado con más frecuencia. Por eso suele estar en la clave principal.
Adam Robinson
1
@CyberSluethOmega: No lo sé; tu pregunta no contiene suficiente información para que pueda tomar una decisión. ¿Querría un índice agrupado en un conjunto de columnas donde las filas se agregarían o eliminarían con frecuencia en otro lugar que no sea al final de la tabla ? No. Pero no estoy muy seguro de por qué preguntas eso o por qué el voto negativo.
Adam Robinson
1
@CyberSluethOmega: Internet puede hacer que los comentarios suenen a la defensiva o fríos cuando no tienen esa intención. Afirmó que dije que no conocía ninguna circunstancia en la que el índice agrupado fuera diferente a la clave principal, cuando de hecho no dije tal cosa. De hecho, lo que dije fue "es inusual ..., pero no imposible", lo que significa que no conozco casos en que esto se hace.
Adam Robinson
14

De ninguna manera soy un experto en SQL ... así que tome esto como la vista de un desarrollador en lugar de una vista de DBA ...

Las inserciones en índices agrupados (ordenados físicamente) que no están en orden secuencial provocan un trabajo adicional para las inserciones / actualizaciones. Además, si tiene muchas inserciones sucediendo a la vez y todas están ocurriendo en la misma ubicación, terminará con contención. Su rendimiento específico varía según sus datos y cómo accede a ellos. La regla general es construir su índice agrupado en el valor estrecho más exclusivo de su tabla (normalmente el PK)

Supongo que su PersonId no cambiará, por lo que las actualizaciones no entran en juego aquí. Pero considere una instantánea de algunas filas con PersonId de 1 2 3 3 4 5 6 7 8 8

Ahora inserte 20 filas nuevas para PersonId de 3. Primero, dado que esta no es una clave única, el servidor agrega algunos bytes adicionales a su valor (detrás de escena) para hacerlo único (que también agrega espacio adicional) y luego la ubicación donde estos residirán tiene que ser alterados. Compare eso con la inserción de un PK de incremento automático donde las inserciones ocurren al final. La explicación no técnica probablemente se reduciría a esto: hay menos trabajo de 'barajar hojas' que hacer si naturalmente progresan valores más altos al final de la tabla en lugar de volver a trabajar la ubicación de los elementos existentes en esa ubicación mientras inserta sus elementos.

Ahora, si tiene problemas con las inserciones, es probable que esté insertando un montón de valores de PersonId iguales (o similares) a la vez, lo que está causando este trabajo adicional en varios lugares de la tabla y la fragmentación lo está matando. La desventaja de cambiar a la PK agrupada en su caso, es que si tiene problemas de inserción hoy en PersonIds que varían en valor distribuidos en toda la tabla, si cambia su índice agrupado a la PK y todas las inserciones ahora ocurren en una ubicación, su problema puede empeorar debido a una mayor concentración de contención. (Por otro lado, si sus inserciones de hoy no están esparcidas por todas partes, pero generalmente están agrupadas en áreas similares, entonces su problema probablemente se aliviará al cambiar su índice agrupado de PersonId a su PK porque estará minimizando el fragmentación.)

Sus problemas de desempeño deben analizarse para su situación particular y tomar este tipo de respuestas solo como pautas generales. Su mejor opción es confiar en un DBA que pueda validar exactamente dónde se encuentran sus problemas. Parece que tiene problemas de contención de recursos que pueden ir más allá de un simple ajuste de índice. Esto podría ser síntoma de un problema mucho mayor. (Problemas de diseño probables ... de lo contrario limitaciones de recursos).

en cualquier caso, buena suerte!

Darian Miller
fuente
5

Algunos autores sugieren no "desperdiciar" el CIen una identitycolumna si hay una alternativa que beneficiaría las consultas de rango.

De las Pautas de diseño de índices agrupados de MSDN, la clave debe elegirse de acuerdo con los siguientes criterios

  1. Se puede utilizar para consultas de uso frecuente.
  2. Proporcionar un alto grado de singularidad.
  3. Se puede utilizar en consultas de rango.

Tu CourtOrderIDcolumna se encuentra 2. Tu PersonIdcumple 1y 3. Como la mayoría de las filas terminarán con el uniqueifieragregado de todos modos, también puede declararlo como único y usarlo, PersonId,CourtOrderIDya que tendrá el mismo ancho pero será más útil ya que la clave de índice agrupado se agrega a todos los NCI como el localizador de filas y esto permitirá para cubrir más consultas.

El problema principal con el uso PersonId,CourtOrderIDcomo CI es que probablemente se producirá una fragmentación lógica (y esto afecta particularmente las consultas de rango que está tratando de ayudar), por lo que necesitaría monitorear el factor de relleno y los niveles de fragmentación y realizar el mantenimiento del índice con más frecuencia.

Martin Smith
fuente
3

Se explica en el siguiente enlace: https://msdn.microsoft.com/en-us/ms190457.aspx

Agrupado

  • Los índices agrupados ordenan y almacenan las filas de datos en la tabla o vista según sus valores clave. Estas son las columnas incluidas en la definición del índice. Solo puede haber un índice agrupado por tabla, porque las filas de datos en sí mismas se pueden ordenar en un solo orden.

  • La única vez que las filas de datos de una tabla se almacenan ordenadas es cuando la tabla contiene un índice agrupado. Cuando una tabla tiene un índice agrupado, la tabla se denomina tabla agrupada. Si una tabla no tiene un índice agrupado, sus filas de datos se almacenan en una estructura desordenada llamada montón.

No agrupado

  • Los índices no agrupados tienen una estructura separada de las filas de datos. Un índice no agrupado contiene los valores clave del índice no agrupado y cada entrada de valor clave tiene un puntero a la fila de datos que contiene el valor clave .

  • El puntero de una fila de índice en un índice no agrupado a una fila de datos se denomina localizador de filas. La estructura del localizador de filas depende de si las páginas de datos se almacenan en un montón o en una tabla agrupada. Para un montón, un localizador de filas es un puntero a la fila. Para una tabla agrupada, el localizador de filas es la clave de índice agrupada.

  • Puede agregar columnas sin clave al nivel de hoja del índice no agrupado para omitir los límites de clave de índice existentes, 900 bytes y 16 columnas de clave, y ejecutar consultas indexadas y totalmente cubiertas.

usuario2191454
fuente
-3

Algunas bases de datos con algunas selecciones desagradables, se unen en un procedimiento almacenado; la única diferencia es el índice

ÍNDICES: agrupados frente a no agrupados

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
fuente