2008-08-28 15 views
21

Si tengo una consulta como:Haz índices trabajar con la cláusula "IN"

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

y tengo un índice en el campo EmployeeTypeId, hace de servidor SQL todavía usan ese índice?

+2

No entiendo por qué esto no es una pregunta real. – nawfal

+0

¿Yo tampoco? Esta es la pregunta exacta que vine a tratar de resolver y me dio una gran información para trabajar. –

+0

+1 para @nawfal - Yo también siento lo mismo. –

Respuesta

13

Sí, eso es correcto. Si su tabla de empleados tiene 10,000 registros, y solo 5 registros tienen identificada USEeypeID (1,2,3), entonces lo más probable es que use el índice para buscar los registros. Sin embargo, si encuentra que 9,000 registros tienen el employeeIDType (1,2,3), lo más probable es que haga un escaneo de tabla para obtener los EmployeeID correspondientes, ya que es más rápido simplemente recorrer toda la tabla que ir a cada rama del árbol de índice y mira los registros individualmente.

SQL Server hace muchas cosas para probar y optimizar cómo se ejecutan las consultas. Sin embargo, a veces no obtiene la respuesta correcta. Si sabe que SQL Server no está utilizando el índice, al consultar el plan de ejecución en el analizador de consultas, puede indicarle al motor de consulta 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 llama Index_EmployeeTypeId.

4

Normalmente lo haría, a menos que la cláusula IN cubra demasiado de la tabla, y luego hará una exploración de 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.

2

Así que hay la posibilidad de que una cláusula de "IN" para ejecutar una exploración de tabla, pero el optimizador tratar de encontrar la mejor manera de tratar con él?

Si se utiliza un índice no hace tanto varían en el tipo de consulta tanto del tipo y la distribución de los datos en la tabla (s), cómo hasta a la fecha en que sus estadísticas de la tabla son, y el tipo de datos real de la columna.

Los otros carteles son correctas que un índice se puede utilizar en una mesa de estudio si:

  • La consulta no tendrá acceso a más de un cierto porcentaje de las filas indexados (por ejemplo ~ 10%, pero debería variar entre los DBMS).
  • Alternativamente, si hay muchas filas, pero relativamente pocos valores únicos en la columna, también puede ser más rápido realizar una exploración de tabla.

La otra variable que puede no ser tan obvia es asegurarse de que los tipos de datos de los valores que se comparan son los mismos. En PostgreSQL, no creo que los índices se utilizarán si está filtrando en un flotador, pero su columna está compuesta de entradas. También hay algunos operadores que no admiten el uso del índice (de nuevo, en PostgreSQL, el operador ILIKE es así).

Como se señaló, siempre verifique el analizador de consultas en caso de duda y la documentación de su DBMS sea su amiga.

3

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

Si los elementos de la lista no fueran únicos, sin embargo, y supongo que en el ejemplo de que "TypeId" es una clave externa, entonces estoy más interesado en la distribución. Me pregunto si el optimizador verificará las estadísticas de cada valor en 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 sea una exploración de tabla. ¿Pero se usará el mismo plan de consulta para los otros dos, incluso si son únicos?

Probablemente sea irrelevante: algo así como una tabla Employee es probable que sea lo suficientemente pequeña como para quedarse en la memoria y probablemente no notaría una diferencia entre eso y la recuperación indexada de todos modos.

Y por último, mientras estoy predicando, tenga cuidado con la consulta en la cláusula IN: a menudo es una manera rápida de hacer que funcione algo y (al menos para mí) puede ser una buena forma de expresar el requisito, pero es casi siempre mejor reformulado como unirme. Su optimizador puede ser lo suficientemente inteligente como para detectar esto, pero puede que no. Si actualmente no compara 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 consultas hasta que tenga una carga completa y estadísticas representativas. Si no puede, prepárese para sorpresas en la producción ...

1

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

Con NHibernate, puede escribir una cláusula así:

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

NHibernate genera entonces una consulta que se parece a

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

Así como usted y otros han señalado, parece que hay va a haber momentos en los que se usará un índice o se realizará un escaneo de tabla, pero no se puede determinar eso hasta el tiempo de ejecución.

0
Select EmployeeId From Employee USE(INDEX(EmployeeTypeId)) 

Esta consulta buscará utilizando el índice que ha creado. Esto funciona para mi. Por favor, intente ...

Cuestiones relacionadas