Regla dura y rápida para incluir columnas en el índice


38

¿Existe alguna regla estricta y rápida para decidir qué columnas y en qué orden se debe incluir en el índice no agrupado. Estaba leyendo esta publicación https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index y encontré eso para la siguiente consulta:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

El póster sugería hacer un índice como este:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

aquí viene mi pregunta por qué no podemos hacer un índice como este

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

o

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

y qué hace que el póster decida mantener la columna Apellido incluida. ¿Por qué no otras columnas? y cómo decidir en qué orden debemos mantener las columnas allí?


3
INCLUDE normalmente debe tener los campos que necesitará DESPUÉS de encontrar un registro, lo que le ahorrará un viaje de ida y vuelta para obtener más datos. El orden de los campos en INCLUDE no es importante.
Jimbo

Ryk, personalmente encuentro útil esta publicación.
Jason Young

Esta pregunta también me parece útil. Centrémonos en buenas preguntas y buenas respuestas en lugar de acechar a las personas ...
Volvox

Respuestas:


47

Esa sugerencia de índice de marc_s está mal. He agregado un comentario. (¡Y fue mi respuesta aceptada también!)

El índice para esta consulta sería

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

Un índice es típicamente

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Dónde:

  • KeyColList = Columnas clave = utilizadas para la restricción de filas y el procesamiento
    DONDE, UNIR, ORDENAR POR, GRUPO POR, etc.
  • NonKeyColList = Columnas sin clave = utilizadas en SELECT y agregación (por ejemplo, SUM (col)) después de la selección / restricción

+1 - ¡Estoy de acuerdo (ver mi respuesta) en que los índices de muestra en OP no tienen valor para la consulta!
JNK

¡Excelente! solo una cosa más, lo que decidirá el orden de KeyColList y NonKeyColList. ¿Puedes explicar con mi ejemplo? Supongamos que ahora mi consulta es SELECCIONAR Id. De empleado, Id. De departamento, Apellido DESDE Empleado DONDE Id. De departamento = 5, Id. De estado = 4 ¿Cómo debería ser el índice ahora?

@Rocky: el NonKeyColListorden no importa. KeyColListel orden debe estar en orden de frecuencia, espera que se usen en consultas. Vea mis notas sobre mi respuesta a continuación, pero es como Last Name, First Name, Middile Initialen una guía telefónica. Necesita el primer campo para encontrar el segundo campo.
JNK

@gbn ¿Realmente necesitamos EmployeeID en la lista de inclusión? Como si tuviéramos un índice agrupado en la columna EmployeeID y, además de esto, si creamos un índice no agrupado en la columna DeptId, el índice NonClustered ya tiene referencia a la clave de agrupación que se incluye en la estructura del índice NonClustered, incluida la clave de agrupación en la lista INCLUDE. No agregue ningún beneficio.
Viswanathan Iyer

1
@ViswanathanIyer no se agregará dos veces al almacenamiento real en disco: SQL Server lo detecta. Por lo tanto, no es necesario, pero aclara las cosas. Sin embargo, no conocemos ningún índice agrupado en la pregunta, por lo que es más seguro asumir que ninguno.
gbn

19

JNK y gbn han dado excelentes respuestas, pero también vale la pena considerar el panorama general, no solo centrarse en una sola consulta. Aunque esta consulta particular podría beneficiarse de un índice (# 1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Este índice no ayuda en absoluto si la consulta cambia ligeramente, como por ejemplo:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Esto necesitaría el índice (# 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Imagine que tiene 1,000 empleados en el Departamento 5. Usando el índice # 1, para encontrar todos los Smiths, necesitaría buscar a través de las 1,000 filas en el Departamento 5, ya que las columnas incluidas no son parte de la clave. Usando el índice # 2, puede buscar directamente al Departamento 5, Apellido Smith.

Por lo tanto, el índice n. ° 2 es más útil para atender una gama más amplia de consultas, pero el costo es una clave de índice más hinchada, lo que hará que las páginas del índice que no son hojas sean más grandes. Cada sistema será diferente, por lo que no hay una regla general aquí.


Como nota al margen, vale la pena señalar que si EmployeeID era la clave de agrupación para esta tabla, suponiendo un índice agrupado, entonces no necesita incluir EmployeeID; está presente en todos los índices no agrupados, lo que significa que el índice # 2 podría simplemente ser

Employee(DepartmentID, LastName)

2
+1 para más información útil. Para su último punto, probé esto y el uso explícito de EmployeeID en INCLUDE en realidad se ignora (según el tamaño del índice) si EmployeeID es el índice agrupado. Aunque es más obvio, creo, y no hay inconveniente en el espacio.
gbn

1
Estoy totalmente de acuerdo: ¡siempre es mejor ser explícito, especialmente si no cuesta nada!

1
Por si acaso ... quiero decir que probé la clave agrupada en INCLUDE (no EmployeeID explícitamente) y no agrega espacio. En las columnas clave lo hace.
gbn

@gbn Sí, la clave del clúster solo necesita residir en el nivel de hoja del índice, que es donde residen las columnas INCLUDE. Moverlo a la clave de índice significaría que también existiría en las páginas que no son hojas. Esto daría como resultado un poco de hinchazón, pero no una cantidad terrible (en las páginas de nivel intermedio, agregaría otros 4 bytes por página de nivel de hoja, suponiendo un número entero).

Esta es una gran respuesta que incluye algunos de los efectos descritos en este artículo: sqlperformance.com/2014/07/sql-indexes/… Si su consulta cambia, también lo hacen los requisitos de sus índices. Puede que esté mejor con la respuesta de Jim, pero puede que le vaya mejor con @gbn answer.
John también conocido como hot2use el

7

No estoy seguro de cómo conseguiste ese primero. Para mí, para esa consulta, usaría:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

No hay una "regla dura y rápida" para prácticamente cualquier cosa en SQL.

Pero, para su ejemplo, el único campo que usará el índice es DepartmentIDporque está en la WHEREcláusula.

Los otros campos solo necesitan ser fácilmente accesibles desde allí. Seleccione en función de DepartmentIDentonces INCLUDEtiene esos campos en el nodo hoja del índice.

No desea utilizar sus otros ejemplos porque no funcionarían para este índice.

Piense en un índice como una guía telefónica. La mayoría de las guías telefónicas están ordenadas por apellido, nombre, inicial del segundo nombre. Si conoce el nombre de alguien, pero no su apellido, la guía telefónica no le sirve de nada, ya que no puede buscar el nombre basado en el orden del índice de la guía telefónica.

Los INCLUDEcampos son como el número de teléfono, dirección, etc. otra información para cada entrada en el libro.

EDITAR:

Para aclarar aún más por qué no usar:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

Este índice solo es útil si tiene uno EmployeeIDo AMBOS EmployeeID y LastNameen su WHEREcláusula. Esto es prácticamente lo OPUESTO de lo que necesita para esta consulta.


@ajbeaven eso es cierto, por lo que el comentario que puse en la edición dice que necesita ya sea el Id. de empleado o ambas columnas.
JNK

durr lo siento mal leído :(
ajbeaven

0

Creo que aún podría usar el índice (employee_id, department_id), pero tendría que incluir una línea 'ficticia' en la frase where, como: "employee_id = employee_id)

  • tener un índice en (employee_id, departemnent_id),
  • tener que buscar / restringir solo en un departamento_id
  • sabiendo que no usará el índice desde un orden incorrecto (o las cosas han cambiado por ahora, y el siguiente "truco" ya no es necesario. ¿Soy un "viejo"?) .
  • Utilice el "viejo" truco?

    seleccione * de Employee emp
    donde emp.employee_id = emp.employee_id
    y emp.department_id = 5

(Por lo tanto, no me estoy centrando en la parte de inclusión aquí de Apellido, sino en el sí / no se usa la clave).

Saludos cordiales,

Miguell


2
No, eso es inútil y no eficiente.
ypercubeᵀᴹ

Específicamente, todavía tendrá que escanear el índice para buscar cada ID de empleado para encontrar todas las instancias de department_id 5. Si hay 1000 empleados y 5 departamentos, SQL tiene que buscar entre los 1000 empleados para encontrar todas las filas de un departamento en particular.
Mark Sowul

Ahora considere el caso opuesto (el índice está en departamento_id, empleado_id). Obviamente, ahora es fácil encontrar un departamento en particular, pero también tenga en cuenta que para encontrar un empleado en particular, SQL solo tiene que escanear a través de 5 departamentos para encontrar todas las filas de un empleado en particular.
Mark Sowul
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.