Selección de índice agrupado: ¿PK o FK?

11

Tengo una tabla de SQL Server 2014 que se parece a la siguiente:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Algunas personas de mi equipo han sugerido que el índice agrupado debería estar activado OrderId, pero creo que el CustomerId+ OrderIdsería una mejor opción por las siguientes razones:

  • Casi todas las consultas se buscarán WHERE CustomerId = @param, noOrderId
  • CustomerIdes una clave externa de la Customertabla, por lo que tener un índice agrupado con CustomerIddebería acelerar las uniones
  • Si bien CustomerIdno es único, tener la OrderIdcolumna adicional especificada en el índice garantizará la unicidad (podemos usar la UNIQUEpalabra clave al crear el índice agrupado en esas 2 columnas, para evitar la sobrecarga de no tener unicidad)
  • Una vez que se insertan los datos, CustomerIdy OrderIdnunca cambian, por lo que estas filas no se moverían después de la escritura inicial.
  • El acceso a los datos se realiza a través de un ORM que solicita todas las columnas de manera predeterminada, por lo que cuando CustomerIdentra una consulta basada en, el índice agrupado podrá proporcionar todas las columnas sin ningún trabajo adicional.

¿El enfoque CustomerIdy OrderIdsuena como la mejor opción dada lo anterior? ¿O es OrderIdmejor por sí solo, ya que es una sola columna que garantiza la unicidad por sí misma?

Actualmente, la tabla tiene un índice agrupado activado OrderIdy un índice no agrupado activado CustomerId, pero no está cubriendo, por lo que dado que estamos usando un ORM y se solicitan todas las columnas, es un trabajo adicional recuperarlos. Entonces, con esta publicación, estoy tratando de considerar mejorar el rendimiento con un CI mejor.

La actividad en nuestra base de datos es de aproximadamente 85% de lecturas y 15% de escrituras.

Andy
fuente

Respuestas:

5

Respuesta wiki comunitaria :

Creo que una clave de índice agrupada compuesta con CustomerID como la primera columna será la mejor, ya que está en la WHEREcláusula de casi todas las consultas.

Puede haber más divisiones en comparación con una clave incremental (o una densidad de página subóptima más probable durante un tiempo si administra y mantiene el factor de relleno para evitar divisiones 'malas'). Sin embargo, la mejora general del rendimiento para las consultas de los clientes es sustancial, ya que se evita la búsqueda de claves.

OrderID o OrderDate pueden ser mejores para la segunda columna, dependiendo de sus consultas más críticas.

Por ejemplo, si los clientes ven una lista cronológica de pedidos recientes después de iniciar sesión en un sitio web, OrderDate debería ser el siguiente, para optimizar ORDER BY OrderDate DESC.

Si elige OrderID como el índice agrupado, con un índice no agrupado en CustomerID , aún obtendrá divisiones y fragmentación, solo en el índice no agrupado.

usuario126897
fuente
3

Si esta tabla es muy intensiva en escritura (por ejemplo INSERT, se están produciendo muchas más declaraciones en lugar de SELECTdeclaraciones en su contra), voy a estar en desacuerdo con la respuesta wiki .

Elegir CustomerID como la primera columna de una clave agrupada compuesta generará muchas divisiones a mitad de página . Es de esperar que tenga muchos clientes existentes y también obtenga muchos clientes nuevos todo el tiempo. Debido a que los clientes están (con suerte) haciendo múltiples pedidos a medida que su negocio continúa creciendo, este enfoque exhibirá una buena cantidad de divisiones a mitad de página que matarán el rendimiento no solo en las escrituras, sino también en las lecturas, ya que sus índices estarán muy fragmentados y probablemente contenga mayores cantidades de espacio en blanco (lo que significa almacenamiento y memoria desperdiciados).

Si cree que CustomerID debería ser una columna principal de un índice agrupado compuesto, puede reducir el impacto de las divisiones de la mitad de la página ajustando FILLFACTORtodos los índices de esta tabla. Esto disminuirá la cantidad de divisiones a mitad de página al aumentar el tamaño de la tabla / índice. Si desea seguir esta ruta, le sugiero que realice pruebas con un valor de 80 y reduzca si el análisis revela que las divisiones a mitad de página todavía están matando el rendimiento.

Mi sugerencia es usar OrderId. OrderID debería ser naturalmente secuencial y generar más divisiones de la página final que son buenas y esperadas con el crecimiento de la tabla. Además, este enfoque funcionará mejor con Particionamiento de tabla si elige usar la columna OrderDate como clave de partición. Con respecto a las consultas que usan constantemente el campo CustomerID, cree un índice no agrupado para manejar esas consultas. Este índice tendría que definirse con el adecuado, FILLFACTORya que sufrirá divisiones a mitad de página que menciono anteriormente, aunque en general no serán tan malas en contraste con si las divisiones se produjeran contra el índice agrupado.

La actividad en nuestra base de datos es de aproximadamente 85% de lecturas y 15% de escrituras.

CustomerID+ OrderID(y especificar un factor de relleno para permitir el crecimiento sin divisiones) probablemente sea mejor si esa evaluación es cierta. Solo asegúrese de que la evaluación sea precisa. Prueba prueba prueba.

John Eisbrener
fuente
1
Tenga en cuenta que insertar un pedido para el último (o único) Cliente en una página no es una "división de página intermedia". Entonces, si los pedidos por cliente son altos, o el ancho de la fila es grande, entonces menos inserciones de pedidos requerirán "divisiones a mitad de página".
David Browne - Microsoft