¿El índice en una columna de identidad no debe estar agrupado?

19

Para una tabla con columna de identidad, ¿se debe crear un PK / índice único agrupado o no agrupado para la columna de identidad?

La razón es que se crearán otros índices para las consultas. ¿Una consulta que usa un índice no agrupado (en un montón) y devuelve columnas que no están cubiertas por el índice usará menos E / S lógica (LIO) porque no hay pasos adicionales de búsqueda de árbol b de índice agrupado?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

El PK agrupado en la columna de identidad es bueno porque:

  1. Aumenta de forma monótona, por lo que no se divide la página al insertarla. Se dice que una inserción masiva puede ser tan rápida como en una tabla de montón (no agrupada)

  2. Es angosto

Sin embargo, ¿las consultas en la pregunta serán más rápidas sin configurarlo en clúster?

** Actualización: ** ¿Qué sucede si Ides el FK de otras tablas y se unirá en algunas consultas?

u23432534
fuente
3
No es mejor ni peor, depende.
Aaron Bertrand
1
@ypercube El enlace kejser.org/clustered-indexes-vs-heaps dice que los que no son de CI tendrán menos LIO.
u23432534
2
He leído el artículo en el pasado y ciertamente señala que hay casos para un índice agrupado y casos para un montón. No todo es negro o todo blanco.
ypercubeᵀᴹ
44
No estoy seguro de que su respuesta a @ypercube satisfaga alguno de los criterios citados por el Sr. Kejser, al menos con los detalles que ha compartido. En su forma actual, no estoy seguro de que esto genere una respuesta útil porque tendría que cubrir casi todos los escenarios, lo que ya se hizo en la publicación del blog que citó. Si puede proporcionar más detalles sobre su escenario específico, entonces tal vez se pueda aplicar parte del conocimiento en la publicación.
swasheck
2
Dependerá de cosas como: a) carga de trabajo (OLTP? OLAP? Etc?), B) tamaño (s) de la tabla, c) forma normal, solo por nombrar algunos. No ha proporcionado detalles sobre ninguno de estos factores, por lo que cualquier recomendación se basaría en conjeturas de su entorno. Además, ¿ha intentado perfilar las consultas que está proponiendo (con búferes borrados) y obtener los perfiles de E / S específicos por configuración y verlos usted mismo?
swasheck

Respuestas:

16

Por defecto, el PK está agrupado y, en la mayoría de los casos, está bien. Sin embargo, qué pregunta debe hacerse:

  • ¿Debería estar mi PK agrupado?
  • ¿Qué columna (s) será la mejor clave para mi índice agrupado?

PK e índice agrupado son dos cosas diferentes:

  • PK es una restricción. PK se utiliza para identificar filas de forma exclusiva, pero no existe una noción de almacenamiento. Sin embargo, de manera predeterminada (en SSMS), se aplica mediante un índice agrupado único si aún no existe un índice agrupado.
  • Los índices agrupados son un tipo especial de índice que almacena datos de fila a nivel de hoja, lo que significa que siempre está cubriendo. Todas las columnas, ya sean parte de la clave o no, se almacenan a nivel de hoja. No tiene que ser único, en cuyo caso se agrega un uniquifier (4 bytes) a la clave en clúster.

Ahora terminamos con 2 preguntas:

  • ¿Cómo quiero identificar de forma exclusiva las filas en mi tabla (PK)
  • ¿Cómo quiero almacenarlo en el nivel de hoja de un índice (índice agrupado)

Depende de cómo:

  • diseñas tu modelo de datos
  • consulta sus datos y escribe sus consultas
  • inserta o actualiza sus datos
  • ...

Primero, ¿necesita un índice agrupado? Si inserta de forma masiva, es más eficiente almacenar datos desordenados en un HEAP (en comparación con los datos ordenados en un clúster). Utiliza RID (Identificador de fila, 8 bytes) para identificar filas de forma exclusiva y almacenarlo en páginas.

El índice agrupado no debe ser un valor aleatorio. Los datos a nivel de hoja serán almacenados y ordenados por la clave de índice. Por lo tanto, debe crecer continuamente para evitar la fragmentación o la división de la página. Si el PK no puede lograr esto, debe considerar otra clave como candidato agrupado. El índice agrupado en columnas de identificación, GUID secuencial o incluso algo así como la fecha de inserción está bien desde un punto de vista secuencial ya que todas las filas se agregarán a la última página de hoja. Por otro lado, si bien un identificador único puede ser útil para las necesidades de su negocio como PK, no deben agruparse (se ordenan / generan al azar).

Si después de algunos análisis de datos y consultas, descubre que utiliza principalmente el mismo índice para obtener sus datos antes de realizar una búsqueda clave en el PK agrupado, puede considerarlo como un índice agrupado, aunque puede que no identifique sus datos de forma exclusiva.

La clave de índice agrupado se compone de todas las columnas que desea indexar. Se agrega una columna de archivo único (4 bytes) si no tiene una restricción única (valor incremental para duplicados, nulo de lo contrario). Esta clave de índice se almacenará una vez para cada fila en el nivel de hoja de todos sus índices no agrupados. Algunos de ellos también se almacenarán varias veces en niveles intermedios (rama) entre la raíz y el nivel de la hoja del árbol de índice (árbol B). Si la clave es demasiado grande, todo el índice no agrupado se hará más grande, requerirá más almacenamiento y más IO, CPU, memoria, ... Si tiene una PK en nombre + fecha de nacimiento + país, es muy probable que esta clave No es un buen candidato. Es demasiado grande para un índice agrupado. El identificador único que usa NEWSEQUENTIALID () generalmente no se considera una clave estrecha (16 bytes) aunque es secuencial.

Luego, una vez que descubrió cómo identificar filas de forma exclusiva en su tabla, puede agregar un PK. Si cree que no lo usará en su consulta, no lo cree agrupado. Aún puede crear otro índice no agrupado si alguna vez necesita consultarlo. Tenga en cuenta que el PK creará automáticamente un índice único.

Los índices no agrupados siempre contendrán la clave agrupada. Sin embargo, si las columnas indexadas (+ columnas clave) están cubriendo, no habrá ninguna búsqueda clave en el índice agrupado. No olvide que también puede agregar Incluir y Dónde a un índice no agrupado. (úsalo con sabiduría)

El índice agrupado debe ser único y lo más estrecho posible El índice agrupado no debe cambiar con el tiempo y debe insertarse de forma incremental.

Ahora es el momento de escribir algunos SQL que crearán la tabla, los índices y las restricciones agrupados y no agrupados.

Todo esto es teórico porque no conocemos su modelo de datos y los tipos de datos utilizados (A y B).

Julien Vavasseur
fuente
11

Para una tabla con una clave primaria (PK) en una columna de identidad, se agrupará de forma predeterminada. ¿Podría ser mejor como no agrupado?

Si está preguntando si el valor predeterminado para una clave principal en una columna de identidad (en particular) no debe estar agrupado, yo diría que no. La mayoría de las tablas se benefician de tener un índice agrupado, por lo que hacer que el agrupamiento sea el valor predeterminado para una restricción de clave principal probablemente sea útil en general, especialmente para los nuevos usuarios de SQL Server.

Al igual que con casi cualquier opción, siempre hay diferentes circunstancias en las que se debe preferir una sobre la otra, pero un DBA experimentado debe conocer el valor predeterminado y poder anularlo cuando sea apropiado. Consulte también las preguntas y respuestas relacionadas, ¿ Cuándo se debe declarar una clave primaria no agrupada? .

¿Las consultas en la pregunta serán más rápidas sin configurarlo en clúster?

Sí, pero con advertencias.

Las búsquedas RID son de hecho más eficientes que las búsquedas clave. Incluso si todas las páginas requeridas están en la memoria (muy probablemente para los niveles superiores de un índice), hay un costo de CPU asociado con la navegación del árbol b de índice agrupado. Como consecuencia, SQL Server generalmente puede realizar muchas más búsquedas de RID que las búsquedas clave por unidad de tiempo de CPU.

Advertencias

Lo anterior a menudo no sería un factor determinante al decidir si estructurar una tabla como un montón o no. Tendría que ser poco práctico para evitar búsquedas (utilizando índices de cobertura), y el número de búsquedas debería ser lo suficientemente grande como para tener un efecto medible (e importante) en el rendimiento, dado el entorno de hardware y la carga de trabajo.

En esta respuesta no es realmente práctico cubrir todos los aspectos del debate sobre el montón versus el índice agrupado, pero diré que hay relativamente pocas buenas razones para preferir estructurar una tabla como un montón en general. Para mí, elegir el tipo de diseño propuesto en la pregunta requeriría un análisis muy cuidadoso antes de la implementación, y tendría que cumplir con una gran exigencia. Los argumentos generales sobre 'escalabilidad' no serían suficientes.

Con respecto a la actualización de la pregunta sobre las uniones, la evaluación del impacto de perder el índice agrupado en los planes de ejecución formaría parte del análisis mencionado anteriormente. Si se utilizan combinaciones de bucles anidados, es muy conveniente tener el índice agrupado en la clave de combinación porque todas las columnas de la fila están disponibles de inmediato sin una búsqueda.

Mi propia experiencia ha sido que tener índices agrupados únicos en columnas de identidad a menudo es beneficioso, se consideran todas las cosas. He encontrado que los montones son problemáticos en términos de administración de espacio, y también debo mencionar que algunas características de SQL Server requieren un índice agrupado único para funcionar.

Paul White dice GoFundMonica
fuente
8

En realidad, no necesita un índice agrupado ni una clave primaria para crearse, ya que los índices únicos e índices no únicos pueden manejar el trabajo. SQL Server ha admitido un índice agrupado desde al menos la versión 1.1, pero la clave primaria era solo un "concepto" que los programadores aplicaron al definir un índice único.

Pero parece que tanto las claves primarias como los índices agrupados son conceptos valiosos en la mayoría de las bases de datos.

Veamos la documentación de SQL Server para ver las descripciones parciales de algunas opciones de indexación como se muestra a continuación.

Índice agrupado: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Los índices agrupados clasifican 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

Clave principal: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Una tabla solo puede contener una restricción PRIMARY KEY.

  • Todas las columnas definidas dentro de una restricción PRIMARY KEY deben definirse como NOT NULL.

  • La clave primaria se puede crear como un índice agrupado (el valor predeterminado si no hay índice agrupado) o un índice no agrupado.

Índice único: https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • Cuando crea una restricción ÚNICA, se crea un índice único no agrupado para aplicar una restricción ÚNICA de forma predeterminada.

  • Puede especificar un índice agrupado ÚNICO si todavía no existe un índice agrupado para la tabla.

Esto significa que su pregunta sobre los índices agrupados y las claves primarias se refiere realmente a algunos de los siguientes problemas. Tenga en cuenta que no todas las tablas se benefician del mismo plan de indexación.

¿Cuándo me beneficiaría que la Clave primaria esté separada del Índice agrupado?

Quizás cuando el índice agrupado es ancho (por ejemplo, 5 columnas de información textual, pero la clave primaria es pequeña (INT o BIGINT), como parece estar describiendo.

  • Un índice agrupado amplio le permitiría seleccionar rápidamente filas del índice para un subconjunto de consultas que proporcionan respuestas seriales del índice agrupado (también conocido como la tabla ). Por ejemplo, un índice agrupado de 5 columnas admitiría escanear las columnas C1, C2, C3, C4, C5 o C1, C2, C3, C4, etc., hasta C1.
  • Nota: Si las filas eran grandes, esto podría darle algunos beneficios de velocidad en la selección de la serie conjunto de filas, especialmente si otras columnas de la tabla se incluyen regularmente en el conjunto de resultados.
  • En ese caso, puede usar la clave primaria para la integridad referencial a fin de proporcionar el valor necesario como clave externa para restringir las filas en otras tablas. El PK es pequeño y, por lo tanto, el FK es un pequeño golpe en el tamaño de las tablas referenciadas.
  • Sin embargo, tenga en cuenta que cualquier índice creado en una tabla que tenga un Índice agrupado incluirá todas las columnas del clúster en los otros índices que cree en esta tabla. Un índice agrupado amplio expandiría el tamaño de todos los índices no agrupados en esa tabla.

¿Debería hacer que la clave primaria sea solo el índice agrupado?

  • Si tiene una clave primaria pequeña (INT o BIGINT) y es el índice agrupado, la sobrecarga de las columnas del clúster es relativamente pequeña. Aunque la Clave primaria agrupada en este caso también existirá en todos los índices de esta tabla, es un precio más bajo que el Wide Cluster discutido anteriormente.

  • Este índice agrupado de clave principal generalmente no ofrecerá directamente una ruta fácil para seleccionar en serie muchas filas.

  • Ahora que ha creado una Clave primaria agrupada, ¿qué pasa con esas otras columnas que alguna vez planeó incluir en el Índice agrupado ?

  • Cree un índice único (o no único) según sea necesario para indexar ese amplio criterio de búsqueda de las columnas C1, C2, C3, C4, C5. Los valores en este índice "Imitación agrupada" pueden servir como una ruta de búsqueda más rápida para esas 5 columnas. Si hay una columna o dos no indexadas que también se seleccionan regularmente, se pueden incluir en el índice con INCLUDE (Doctor_Name, Diagnosis_Synopsis).

Aunque encuentro útiles los índices agrupados y las claves primarias simples, hay algunas buenas razones para pensar si usarlos en una tabla o en una base de datos.

¿Necesita un índice agrupado?

  • Si crea índices (índices únicos e índices no únicos) y define la clave primaria sin la sobrecarga de ser un índice agrupado, es posible que los índices más limitados le brinden lo que necesita para sus consultas.

  • Hay algunos comportamientos útiles en los índices agrupados y las claves primarias, pero recuerde que son realmente los índices los que más importan. Diseñe la estrategia de indexación para tener en cuenta las realidades de su aplicación. Quizás OneBigTablenecesite tener una estrategia de indexación diferente de la que usa para la mayoría de las tablas.

  • Sin un índice agrupado, sus datos se almacenarán como un montón con el Identificador de fila (RID), que no es un buen mecanismo de búsqueda. Pero, como se mencionó anteriormente, puede crear índices únicos y no únicos para manejar sus consultas.

Lo que ahora te lleva a considerar los montones:

Montones e índices: https://msdn.microsoft.com/en-us/library/hh213609.aspx

  • Cuando una tabla se almacena como un montón, las filas individuales se identifican por referencia a un identificador de fila (RID) que consiste en el número de archivo, el número de página de datos y el espacio en la página. El id de la fila es una estructura pequeña y eficiente. (Pero no es un índice ).
  • A veces, los arquitectos de datos usan montones cuando siempre se accede a los datos a través de índices no agrupados y el RID es más pequeño que una clave de índice agrupado .

Pero si también tiene algunos 'puntos críticos' en un gran conjunto de datos, también puede buscar otro tipo de índice:

Índice filtrado: https://msdn.microsoft.com/en-us/library/cc280372.aspx

  • Un índice filtrado bien diseñado mejora el rendimiento de la consulta y la calidad del plan de ejecución porque es más pequeño que un índice no agrupado de tabla completa y tiene estadísticas filtradas. Las estadísticas filtradas son más precisas que las estadísticas de la tabla completa porque cubren solo las filas del índice filtrado .

  • Los índices filtrados tienen una serie de restricciones que se describen en el enlace a los índices filtrados.

Sin embargo, si está interesado en pensar en la posibilidad de omitir las Claves primarias y los Índices agrupados, puede leer la publicación de Markus Winand vinculada a continuación. Él demuestra sus razones, con algunos ejemplos de código, para sugerir que a veces puede ser una buena idea renunciar al uso de esas características.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

Pero finalmente todo vuelve a comprender su aplicación y diseñar el código, las tablas, los índices, etc. para adaptarse al trabajo que está haciendo.

RLF
fuente
Por lo que vale, en mi trabajo diario si encuentro una tabla que es un montón, considero que probablemente sea un error y verifico con los desarrolladores para ver si se hizo un montón intencionalmente.
RLF
-2

Un par de puntos a considerar.

Si bien un índice (agrupado o no) en un valor que aumenta de manera monótona ahorra divisiones de página durante las inserciones masivas, crea un nuevo punto caliente en el extremo posterior del índice. Aunque puede no ser un problema con una inserción masiva de un solo hilo, definitivamente aumentará la contención para una aplicación multiproceso que inserte nuevas tuplas a una velocidad alta, ya que los hilos competirán constantemente por el acceso a la última página del índice.

Agrupar la tabla en función de un PK sustituto (identidad) rara vez es beneficioso. Dicha clave primaria se usa principalmente para acceder a tuplas individuales, una a la vez, o escanear todo el índice en busca de uniones. En cualquier caso, no importa si el índice está agrupado o no (con la excepción de combinaciones de combinación, puede ser, pero ¿con qué frecuencia son?)

Creo que se beneficiará más de un índice agrupado que cubre consultas que solicitan un escaneo de rango clave y predicados adicionales que hacen referencia a otras columnas.

mustaccio
fuente
¿Qué tan alta debe ser la tasa para que esto se convierta en un problema?
ypercubeᵀᴹ
@ypercube ¿puedo decir "depende"? Porque lo hace En ausencia de desencadenantes en la mesa, esperaría comenzar a experimentar cierta disputa con una docena de hilos con un total de 1K inserciones por segundo.
mustaccio
No estoy en desacuerdo, pero estaba preguntando qué tan lejos se puede llegar con un solo punto caliente. Recuerdo haber visto un artículo sobre la inserción de 30K filas por segundo en una tabla con IDENTITY como CI (si la memoria me sirve bien) pero no puedo encontrar la publicación del blog.
ypercubeᵀᴹ
Esta discusión no tiene sentido en ausencia de una carga de trabajo concreta que se ejecute contra un esquema concreto en un hardware específico. Espero que todos podamos estar de acuerdo en que un índice en una secuencia monótonamente creciente creará un "punto caliente"; si creará un cuello de botella inaceptable y si uno debería preocuparse por ello o no, depende de las circunstancias.
mustaccio