Pregunta

Si tengo una consulta como:

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3)

y tengo un índice sobre el EmployeeTypeId campo, ¿el servidor SQL todavía usa ese índice?

¿Fue útil?

Solución

Sí es cierto.Si su tabla de empleados tiene 10,000 registros y solo 5 registros tienen ID de tipo de empleado en (1,2,3), lo más probable es que use el índice para recuperar los registros.Sin embargo, si encuentra que 9.000 registros tienen el tipo de ID de empleado en (1,2,3), lo más probable es que simplemente realice un escaneo de la tabla para obtener los ID de empleado correspondientes, ya que es más rápido recorrer toda la tabla que ir a cada rama del árbol de índice y observe los registros individualmente.

SQL Server hace muchas cosas para intentar optimizar la forma en que se ejecutan las consultas.Sin embargo, a veces no obtiene la respuesta correcta.Si sabe que SQL Server no está usando el índice, al observar el plan de ejecución en el analizador de consultas, puede indicarle al motor de consultas que use un índice específico con el siguiente cambio en su consulta.

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId )) Where EmployeeTypeId IN (1,2,3)

Suponiendo que el índice que tiene en el campo EmployeeTypeId se denomina Index_EmployeeTypeId.

Otros consejos

Por lo general, lo haría, a menos que la cláusula IN cubra demasiado de la tabla, y luego realizará un escaneo de la tabla.La mejor manera de averiguarlo en su caso específico sería ejecutarlo en el analizador de consultas y verificar el plan de ejecución.

A menos que la tecnología haya mejorado en formas que no puedo imaginar últimamente, la consulta "IN" que se muestra producirá un resultado que es efectivamente el OR de tres conjuntos de resultados, uno para cada uno de los valores en la lista "IN".La cláusula IN se convierte en una condición de igualdad para cada uno de la lista y utilizará un índice si corresponde.En el caso de ID únicos y una tabla lo suficientemente grande, esperaría que el optimizador use un índice.

Sin embargo, si los elementos de la lista no fueran únicos y supongo que en el ejemplo un "TypeId" es una clave externa, entonces estoy más interesado en la distribución.Me pregunto si el optimizador comprobará las estadísticas de cada valor de la lista.Digamos que verifica el primer valor y descubre que está en el 20% de las filas (de una tabla lo suficientemente grande como para importar).Probablemente escaneará la tabla.Pero, ¿se utilizará el mismo plan de consulta para los otros dos, incluso si son únicos?

Probablemente sea discutible: es probable que algo como una tabla de Empleados sea lo suficientemente pequeña como para permanecer almacenada en la memoria caché y, de todos modos, probablemente no notarás una diferencia entre eso y la recuperación indexada.

Y por último, mientras predico, tenga cuidado con la consulta en la cláusula IN:A menudo es una forma rápida de hacer que algo funcione y (al menos para mí) puede ser una buena manera de expresar el requisito, pero casi siempre es mejor reformularlo como una unión.Su optimizador puede ser lo suficientemente inteligente como para detectar esto, pero también puede que no sea así.Si actualmente no verifica el rendimiento con los volúmenes de datos de producción, hágalo; en estos días de optimización basada en costos no puede estar seguro del plan de consulta hasta que tenga una carga completa y estadísticas representativas.Si no puedes, entonces prepárate para sorpresas en la producción...

Entonces, existe el potencial de una cláusula "en" para ejecutar un escaneo de mesa, pero ¿el optimizador intentará resolver la mejor manera de lidiar con él?

El uso de un índice no depende tanto del tipo de consulta sino del tipo y la distribución de los datos en las tablas, de qué tan actualizadas estén las estadísticas de la tabla y del tipo de datos real de la columna. .

Los otros carteles tienen razón en que se utilizará un índice sobre un escaneo de tabla si:

  • La consulta no accederá a más de un cierto porcentaje de las filas indexadas (digamos ~10%, pero debe variar entre DBMS).
  • Alternativamente, si hay muchas filas, pero relativamente pocos valores únicos en la columna, también puede ser más rápido realizar un escaneo de la tabla.

La otra variable que podría no ser tan obvia es asegurarse de que los tipos de datos de los valores que se comparan sean los mismos.En PostgreSQL, no creo que se utilicen índices si estás filtrando por un flotante pero tu columna está formada por enteros.También hay algunos operadores que no admiten el uso de índices (nuevamente, en PostgreSQL, el operador ILIKE es así).

Sin embargo, como se señaló, siempre verifique el analizador de consultas cuando tenga dudas y la documentación de su DBMS es su amiga.

@Miguel:Gracias por el análisis detallado.Definitivamente hay algunos puntos interesantes que mencionas allí.El ejemplo que publiqué es algo trivial, pero la base de la pregunta surgió del uso de NHibernate.

Con NHibernate, puedes escribir una cláusula como esta:

int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))

NHibernate luego genera una consulta que se parece a

select * from employee where employeeid in (1, 5, 23463, 32523)

Entonces, como usted y otros han señalado, parece que habrá momentos en los que se utilizará un índice o se realizará un escaneo de tabla, pero realmente no se puede determinar eso hasta el tiempo de ejecución.

Select EmployeeId From Employee USE(INDEX(EmployeeTypeId))

Esta consulta buscará utilizando el índice que ha creado.Esto funciona para mi.Por favor inténtalo..

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top