2012-02-26 7 views
10

i solía escribir statments SQL comoes "donde (Paramid = @ParamID) OR (@ParamID = -1)" una buena práctica en la selección sql

select * from teacher where (TeacherID = @TeacherID) OR (@TeacherID = -1) 

read more

y pasar @TeacherID valor = -1 para seleccionar todos los maestros

ahora me preocupa el rendimiento ¿me puede decir que es una buena práctica o una mala?

muchas gracias

+1

George, no puedes imaginarte cuán "caliente" es tu pregunta. Acabas de crear una excelente combinación de "mejores prácticas" y "SQL" en una sola pregunta. Agregué +1, agregaría +100 si pudiera. –

+0

Por lo general, escribo dos consultas separadas, tal como sugiere @Jeff O. También es posible que desee leer sobre el rastreo de parámetros. SQL dinámico y RECOMPILE pueden ser más caros en este caso; solo tenemos dos escenarios distintos. –

Respuesta

6

Si TeacherID se indexa y que están pasando un valor distinto de -1 como TeacherID para buscar datos de un maestro específico, entonces esta consulta va a terminar haciendo un escaneo completo de tabla en lugar de la opción potencialmente mucho más eficiente de buscar en el índice para recuperar los detalles del maestro específico ...

... A menos que esté en SQL 2008 SP1 CU5 y posterior y utilice la sugerencia OPTION (RECOMPILE). Ver Dynamic Search Conditions in T-SQL para el artículo definitivo sobre el tema.

+1

+1 para el enlace al trabajo de Erland. Esa es absolutamente la respuesta. – NotMe

6

Utilizamos esto de una forma muy limitada en los procedimientos almacenados.

El problema es que el motor de base de datos no puede mantener un buen plan de consulta para él. Cuando se trata de una gran cantidad de datos, esto puede tener un grave impacto negativo en el rendimiento.

Sin embargo, para conjuntos de datos más pequeños (yo diría que menos de 1000 registros, pero eso es una suposición) debería estar bien. Tendrá que probar en su entorno particular.

Si está en un procedimiento almacenado, es posible que desee incluir algo así como una opción WITH RECOMPILE para que plan is regenerated on each execution. Esto agrega (ligeramente) al tiempo de cada ejecución, pero en varias ejecuciones puede reducir el tiempo de ejecución promedio. Además, esto permite que la base de datos inspeccione la consulta real y "short circuit" las partes que no son necesarias en cada llamada.

Si está creando directamente su SQL y transfiriéndolo, le sugiero que haga que la parte que construye su sql sea un poco más inteligente para que solo incluya la parte de la cláusula where que realmente necesita.


Otra ruta que puede considerar es utilizar las consultas de UNION ALL en lugar de los parámetros opcionales. Por ejemplo:

SELECT * FROM Teacher WHERE (TeacherId = @TeacherID) 
UNION ALL 
SELECT * FROM Teacher WHERE (@TeacherId = -1) 

Esto realmente logra exactamente lo mismo; sin embargo, el plan de consulta es almacenable en caché. También hemos usado este método en algunos lugares y hemos visto mejoras en el rendimiento con respecto al uso WITH RECOMPILE. No hacemos esto en todas partes porque algunas de nuestras consultas son extremadamente complicadas y prefiero tener un impacto en el desempeño que complicarlas aún más.

Sin embargo, al final debes hacer muchas pruebas.


Hay una segunda parte aquí que debe reconsiderar. SELECT *. It is ALWAYS preferable to actually name the columns you want returned y para asegurarse de que está solo devolviendo las que realmente necesitará. Mover datos a través de los límites de la red es muy costoso y, en general, puede obtener una buena cantidad de impulso de rendimiento simplemente especificando exactamente lo que desea. Además, si lo que necesita es muy limitado, a veces puede hacer covering indexes para que el motor de base de datos ni siquiera tenga que tocar las tablas subyacentes para obtener los datos que desea.

+0

Su 'UNION ALL' asume que 'TeacherId' nunca puede ser -1, entonces me pregunto, ¿es posible poner eso en una restricción de alguna manera de tal manera que SQL Server pueda descubrir un buen plan por sí mismo? – hvd

+2

@hvd: es extremadamente raro que alguien use un número negativo para un Id. Hasta el punto de que, si se encuentra en esta situación, debe pasar el nulo y probarlo en lugar de usar -1 – NotMe

+0

. Lo sé, pero mi punto es que el optimizador de consultas SQL Server no. – hvd

3

Si realmente está preocupado por el rendimiento, puede dividir su procedimiento para llamar a dos procesos diferentes: uno para todos los registros y otro basado en el parámetro.

If @TeacherID = -1 
    exec proc_Get_All_Teachers 
else 
    exec proc_Get_Teacher_By_TeacherID @TeacherID 

Cada uno puede optimizarse individualmente.

Es su sistema, compare el rendimiento. Considere la optimización de la opción más popular. Si la mayoría de los usuarios van a seleccionar un solo registro, ¿por qué ocultar su rendimiento solo para acomodar a los pocos que seleccionan a todos los profesores (y deben tener una expectativa razonable de rendimiento).

Sé que una consulta de selección única es más fácil de mantener, pero en algún momento la facilidad de mantenimiento finalmente da paso al rendimiento.

+0

Para una situación simple como la OP mostró, esto estaría bien. Sin embargo, no es mantenible si el número de parámetros de búsqueda opcionales es más de 1. Por ejemplo, si fuera 2, tendría que tener 4 s'procs ... – NotMe

+0

@ChrisLively - SQL Server 2008 permitirá el paso de un parámetro de valor de tabla. La instrucción select dentro del proceso podría usar eso en lugar de un parámetro de valor único. – JeffO

Cuestiones relacionadas