¿Cuándo debe declararse una clave primaria no agrupada?

169

Mientras creaba una base de datos de prueba para otra pregunta que pregunté anteriormente, recordé que una Clave primaria puede ser declarada NONCLUSTERED

¿Cuándo usaría una NONCLUSTEREDclave primaria en lugar de una CLUSTEREDclave primaria?

Gracias por adelantado

Stuart Blackler
fuente

Respuestas:

188

La pregunta no es "cuándo debería ser PK", sino que debería preguntarse "¿cuál es la clave adecuada para el índice agrupado"?

Y la respuesta realmente depende de cómo se consultan los datos . El índice agrupado tiene una ventaja sobre todos los demás índices: dado que siempre incluye todas las columnas, siempre está cubriendo. Por lo tanto, las consultas que pueden aprovechar el índice agrupado ciertamente no necesitan usar búsquedas para satisfacer algunas de las columnas y / o predicados proyectados.

Otra pieza del rompecabezas es cómo se puede usar un índice . Hay tres patrones típicos:

  • sondeos, cuando se busca un único valor clave en el índice
  • escaneos de rango, cuando se recupera un rango de valores clave
  • ordenar por requisitos, cuando un índice puede satisfacer un pedido sin requerir un orden de parar y continuar

Entonces, si analiza su carga esperada (las consultas) y descubre que una gran cantidad de consultas usaría un índice particular porque usan un cierto patrón de acceso que se beneficia de un índice, tiene sentido proponer ese índice como el índice agrupado.

Otro factor más es que la clave de índice agrupada es la clave de búsqueda utilizada por todos los índices no agrupados y, por lo tanto, una clave de índice agrupada amplia crea un efecto dominó y amplía todos los índices no agrupados y los índices amplios significan más páginas, más E / S , más memoria, menos bondad.

Un buen índice agrupado es estable , no cambia durante la vida útil de la entidad, porque un cambio en los valores clave del índice agrupado significa que la fila debe eliminarse e insertarse nuevamente.

Y un buen índice agrupado crece en orden no al azar (cada valor de clave recién insertado es mayor que el valor anterior) para evitar divisiones de página y fragmentación (sin perder el tiempo con FILLFACTORs).

Entonces, ahora que sabemos qué es una buena clave de índice agrupada, ¿la clave primaria (que es una propiedad lógica de modelado de datos) cumple con los requisitos? En caso afirmativo, entonces el PK debe agruparse. Si no, entonces la PK no debe estar agrupada.

Para dar un ejemplo, considere una tabla de hechos de ventas. Cada entrada tiene una ID que es la clave principal. Pero la gran mayoría de las consultas solicitan datos entre una fecha y otra fecha, por lo tanto, la mejor clave de índice agrupada sería la fecha de venta , no la ID . Otro ejemplo de tener un índice agrupado diferente de la clave primaria es una clave de selectividad muy baja, como una 'categoría' o un 'estado', una clave con muy pocos valores distintos. Tener una clave de índice agrupada con esta clave de baja selectividad como la tecla más a la izquierda, por ejemplo (state, id), a menudo tiene sentido debido a los escaneos de rangos que buscan todas las entradas en un "estado" particular.

Una última nota sobre la posibilidad de una clave primaria no agrupada sobre un montón (es decir, no hay ningún índice agrupado). Este puede ser un escenario válido, la razón típica es cuando el rendimiento de inserción masiva es crítico, ya que los montones tienen un rendimiento de inserción masiva significativamente mejor en comparación con los índices agrupados.

Remus Rusanu
fuente
1
¿Qué significa "ordenar por requisitos, cuando un índice puede satisfacer un pedido sin requerir un orden de parar y seguir" aquí?
Mike Sherrill 'Cat Recall'
2
@RemusRusanu. +1 Respuesta muy útil. Una pregunta sobre el ejemplo (state, id). En este ejemplo, el requisito de "buen índice agrupado crece en orden no al azar" no se cumplirá, ¿no es así? Entonces, ¿podemos considerarlo como un buen índice agrupado?
LCJ
26

La razón básica para usar índices agrupados se establece en Wikipedia :

La agrupación altera el bloque de datos en un cierto orden distinto para que coincida con el índice, lo que da como resultado que los datos de la fila se almacenen en orden. Por lo tanto, solo se puede crear un índice agrupado en una tabla de base de datos determinada. Los índices agrupados pueden aumentar en gran medida la velocidad general de recuperación, pero generalmente solo cuando se accede a los datos secuencialmente en el mismo orden o en el orden inverso del índice agrupado , o cuando se selecciona un rango de elementos.

Digamos que tengo una tabla de personas, y estas personas tienen una columna de país y una clave primaria única. Es una tabla demográfica, así que estas son las únicas cosas que me importan; qué país y cuántas personas únicas están vinculadas a ese país.

Por lo tanto, solo es probable que SELECCIONE DONDE O PEDIR POR la ​​columna País; un índice agrupado en la clave primaria no me sirve de nada, no estoy accediendo a estos datos por PK, estoy accediendo a ellos por esta otra columna. Como solo puedo tener un índice agrupado en una tabla, declarar mi PK como Agrupado me impediría usar un Índice agrupado en el país.

Además, aquí hay un buen artículo sobre índices agrupados vs índices no agrupados, resulta que los índices agrupados causaron problemas de rendimiento de inserción en SQL Server 6.5 (que al menos con suerte no es relevante para la mayoría de nosotros aquí).

Si coloca un índice agrupado en una columna IDENTIDAD, todas sus inserciones se realizarán en la última página de la tabla, y esa página estará bloqueada durante la duración de cada IDENTIDAD. No es gran cosa ... a menos que tenga 5000 personas que quieran la última página Entonces tienes mucha contención por esa página

Tenga en cuenta que este no es el caso en versiones posteriores.

Ben Brocka
fuente
3
FIY, mencionó SQL Server 6.5: dba.stackexchange.com/questions/1584/…
gbn
15

Si su clave principal es de UNIQUEIDENTIFIER, asegúrese de especificar que es NONCLUSTERED. Si lo agrupa, cada inserción tendrá que hacer una combinación de registros para insertar la nueva fila en la posición correcta. Esto hará que el rendimiento del tanque.

Bryan Johns
fuente
1
Si bien trato de evitar UUID para claves agrupadas, creo que el razonamiento anterior puede estar incompleto. El servidor SQL no necesariamente reorganiza las filas para insertar un en la posición correcta (si quiere decir "entre el valor más bajo y más alto"). Considere una inserción en el medio de una tabla de billones de filas. Se necesita indirección adicional, que puede ser lo que quisiste decir. UNIQUEIDENTIFIERTambién existe un tipo secuencial y tiene la misma probabilidad de generar claves únicas, aunque todavía tiene un tamaño de 128.
Charles Burns
8

Un ejemplo muy común:

  • Customermesa con CustomerIDcomoCLUSTERED PRIMARY KEY
  • Tabla de pedidos con OrderID (PK), CustomerID, OrderDatey algunas otras columnas
  • OrderPositions con OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
  • tienes que indexar las tablas de pedidos

Por supuesto, "depende" es, como casi siempre, la respuesta correcta, pero la mayoría de las aplicaciones (no BI-Reports) funcionarán en función del cliente (por ejemplo, inicie sesión como cliente 278 en el sitio web y haga clic en "Mis pedidos" o el secretario enumera todos los pedidos del cliente 4569 o su rutina de facturación resumirá todos los pedidos del cliente 137).

En este caso, no tendría mucho sentido agrupar la tabla por OrderID. Sí, tendrá consultas SELECT ... WHERE OrderId = ?para enumerar los detalles del pedido, pero esto generalmente sería una búsqueda de índice corta y barata (3 lecturas).

Por otro lado, si agrupara su Ordertabla por CustomerID, no tendría que hacer múltiples búsquedas de claves cada vez que consulta la tabla CustomerId = ?.

El CLUSTERED INDEXdebe haber siempre UNIQUE, de lo contrario SQL Server añadiría una (= inservible) columna INT invisible UNIQUIFIERpara asegurar la uniquiness - y sería mucho más sentido para agregar datos reales (utilizables) a continuación algunas cosas al azar (en función del orden de inserción).

Debido a que un cliente (con suerte) realizará más de un pedido, tendremos que agregar el OrderIDo (si normalmente ordena esto) el OrderDate(si es una fecha y hora; de lo contrario, el cliente estaría limitado a un pedido por día) a el CLUSTERED INDEXy terminar con:

CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)

Las mismas reglas se aplican a la OrderPositionstabla. Por lo general, la mayoría de las consultas enumerarán todas las posiciones para un orden específico, por lo que debe crear el PK con el OrderPositionIDas NONCLUSTEREDy UNIQUE CLUSTERED INDEXel a OrderId, OrderPositionID.

Por cierto: es correcto que la Customertabla esté agrupada por su PK (la CustomerID, porque es una "Tabla de nivel superior" y, en una aplicación típica, será consultada principalmente por su CustomerID.

Las tablas de búsqueda puras como eg Genderso InvoiceTypesor PaymentTypeson otro ejemplo de tablas que deberían estar agrupadas por su PK (porque normalmente las unirás en GenderId, InvoiceTypeIdo PaymentTypeId).

Thomas Franz
fuente
2

Cuando se considera que un índice agrupado es más beneficioso para el sistema en general que una PK agrupada mediante el uso de alguna medida de rendimiento. Solo puede haber un índice agrupado en una tabla.

Ejemplos de medidas de rendimiento son el tiempo de consulta único (velocidad), la integración de los tiempos de consulta totales contra la tabla (eficiencia) y la necesidad de agregar muchas columnas de inclusión a un índice no agrupado muy grande para lograr un rendimiento similar al agrupado (tamaño )

Esto puede suceder cuando los datos generalmente se recuperan utilizando un índice que no es único, contiene valores nulos (no permitidos en una PK), o la PK se agregó por una razón secundaria (como la replicación o la identificación del registro de seguimiento de auditoría).

crokusek
fuente