2008-11-05 9 views
6

Tengo un procedimiento almacenado que tiene un parámetro opcional, @UserID VARCHAR(50). La cuestión es que hay dos maneras de trabajar con él:SQL En cuanto a rendimiento, lo que es mejor: ¿una cláusula IF ... ELSE o una cláusula WHERE LIKE?

  1. darle un valor por defecto de NULL, el tener una cláusula IF...ELSE, que realiza dos SELECT consultas diferentes, uno con 'WHERE UserID = @UserID' y sin el dónde.
  2. Déle un valor predeterminado de '%' y luego simplemente use la cláusula where use 'WHERE UserID LIKE @UserID'. En el código de llamada, no se usará '%', por lo que solo se encontrarán las coincidencias exactas.

La pregunta es: ¿Qué opción es más rápida? ¿Qué opción proporciona un mejor rendimiento a medida que crece la tabla? Tenga en cuenta que la columna UserID es una clave externa y no está indexada.

EDIT: Algo que quiero añadir, basado en algunas respuestas: El parámetro @UserID no es (necesariamente) que se pasa el único parámetro opcional . En algunos casos, hay hasta 4 o 5 parámetros opcionales.

+0

Te lo ruego ... no vayas con la respuesta que aceptaste. Es un camino seductor que conduce al dolor y la miseria. –

+0

Mark, leí su respuesta y me ha convencido. Lo único ahora, como se menciona en otro comentario: ¿Cómo manejas múltiples parámetros opcionales? La forma en que se hace ahora en nuestro DB es concatenar una cadena WHERE, agregar eso a la cadena SQL y llamar a EXEC() sobre eso. hay una manera mas facil? – Schmuli

+0

Otra opción es escribir código que escribe código. Si necesita 5 PLANES distintos, escriba un programa que genere esos 5 SQL y las declaraciones de casos que determinan qué sql hace qué grupo de variables. Pero no ejecute su metacódigo, tome la salida y verifique eso en CVS. el metacódigo es para su uso. –

Respuesta

7

Lo que suelen hacer es algo así como

WHERE (@UserID IS NULL OR UserID = @UserID) 

Y por qué no es así indexados? Por lo general es una buena forma de FKs índice, ya que a menudo se unen en ellos ...

Si usted está preocupado acerca de almacenamiento plan de consulta, sólo tiene que hacer: CREATE PROCEDURE ... CON RECOMPILE

+0

Antes de SQL Server 2008 SP1 CU5 esto es terrible. Si está en una versión posterior, agregar 'OPTION (RECOMPLO)' a la consulta hace que esta sea una forma viable de implementar condiciones dinámicas de búsqueda. (Según lo investigado por Erland Sommarskog) –

3

La única manera de Dígalo con certeza es implementar ambos y medir. A modo de referencia, hay una tercera forma de implementar esto, que es lo que suelo utilizar:

WHERE (@UserID IS NULL OR UserId = @UserId) 
2

Por qué no usar:

where @UserID is null or [email protected] 

+ el mantenimiento y el rendimiento

+0

¿Estás forzando un análisis crítico todas y cada una de las veces? –

+0

No- optimizier debería tenerlo en cuenta. –

1

que había desafiante vaya con el primero porque, aunque es menos "inteligente", es más fácil entender lo que está pasando y, por lo tanto, será más fácil de mantener.

El uso de la opción predeterminada especial significado es probable que dispararle para arriba más adelante con algún involuntario efecto secundario (documentación de por qué usted está usando ese defecto y es de uso es probable que se pierda por cualquier mantenedor)

En cuanto a la eficiencia, a menos que busque 1.000 usuarios o más, es poco probable que sea un problema suficiente para anular la capacidad de mantenimiento.

+0

Podría besarte. Pero no ceda a los malos hábitos porque los datos pueden ser pequeños ... si lo hace donde no importará, continuará haciéndolo si fuera importante y se lo rociara con una manguera. –

+0

Sí, evitaré los besos pero en realidad quise decir al revés: siempre busque un código obvio y claro a menos que los problemas de rendimiento * lo fuercen de otra manera Y siempre recuerde que los ciclos de la máquina son mucho más baratos que los ciclos del codificador. – Cruachan

1

En primer lugar, debe crear un índice para UserID si lo usa como criterio de búsqueda de esta manera.

En segundo lugar, al comparar UserID LIKE @UserID no se puede usar un índice, porque el optimizador no sabe si se dará un valor de parámetro @UserID que comience con un comodín. Tal valor no puede usar el índice, por lo que el optimizador debe suponer que no puede crear un plan de ejecución utilizando ese índice.

por lo que recomiendo:

  1. crear un índice en UserID
  2. utilizar la primera opción, WHERE UserID = @UserID, que debe ser optimizado para utilizar el índice.

edición: Marca Brady me recuerda que se olvidó de abordar el caso NULL. Estoy de acuerdo con la respuesta de Mark, haga el IF y ejecute una de las dos consultas. Doy la respuesta de Mark +1.

+0

Y cuando no hay User_ID, ¿cuándo los quiere todos? No has respondido completamente la pregunta. Usted manejó la mitad de eso es simple. –

+0

Dónde UserId Como @IDUsuario utilizará un índice, si está disponible, siempre y cuando el valor de @IDUsuario No incluye un comodín al principio de la cadena de valor ... como en Dónde lastname como '%' Higgins Si tuviste Donde Apellido 'Higgins' O Donde Apellido 'Higgins%' Entonces está bien –

+0

@Charles: como yo lo entiendo, eso requeriría recompilar el plan de ejecución con respecto al valor dado de @UserID. De lo contrario, es posible que el optimizador no pueda asumir que puede usar el índice. –

0

Me gustaría elegir la opción 1, pero en realidad tengo dos procedimientos almacenados. Uno obtendría todos los usuarios y uno obtendría un usuario específico. Creo que esto es más claro que pasar en un NULO. Este es un escenario en el que desea dos sentencias SQL diferentes porque está pidiendo cosas diferentes (todas las filas frente a una fila).

+0

Podría hacer eso, aunque: 1. La cláusula WHERE aún puede devolver más de una fila, 2. Hay parámetros opcionales adicionales, y 3. Es más fácil para la lógica en el código tener un SP y solo pasar los parámetros necesarios . – Schmuli

+0

He utilizado el enfoque NULL-means-everything antes y se ha quemado cuando el código erróneo pasa en NULL para todo. Luego, la base de datos se activa y obtiene un millón de filas. –

2

El problema con tener sólo un procedimiento almacenado es como se ha mencionado anteriormente bastante bien que el SQL almacena un plan compilado para el procedimiento, un plan para nula es bastante diferente a uno con un valor.

Sin embargo, la creación de una sentencia if en el procedimiento almacenado dará lugar al procedimiento almacenado se vuelve a compilar en tiempo de ejecución. Esto también puede agregar problemas de rendimiento.

Como se mencionó en otra parte, esta es adecuado para una prueba y ver enfoque, teniendo en cuenta la sentencia if, un @IDUsuario es nulo y dos procedimientos separados.

Por desgracia, la velocidad de estos enfoques va a variar en gran medida basado en la cantidad de datos y la frecuencia de las llamadas en las que el parámetro es nulo vs las llamadas en las que el parámetro no es. De nuevo, la cantidad de parámetros también afectará la eficacia de un enfoque que requiere volver a escribir los procedimientos.

Si está utilizando SQL 2005, puede obtener algún provecho de la consulta plan hint option.

Corrección: SQL 2005 y desde entonces ha "sentencia de nivel Recopilación" que almacenan en caché planes separados para cada instrucción en un procedimiento ... Así que la vieja política pre-2005 de no poner múltiples sentencias rama lógica en un solo procedimiento almacenado ya no es cierto ... - Charles Bretana (me imagino que esto fue lo suficientemente importante como para elevarlo de un comentario)

+0

Sql 2005 y desde entonces tiene "recompilación de nivel de instrucción" que almacena separatye planes en caché para cada instrucción en un procedimiento ... Así que la vieja política anterior a 2005 de no poner múltiples instrucciones de rama lógica en un solo procedimiento almacenado ya no es verdad ... –

3

SQL Server 2005 y posteriores tienen algo llamado "recompilación a nivel de sentencia". Confirmar http://www.microsoft.com/technet/prodtechnol/sql/2005/recomp.mspx

Básicamente, cada declaración individual ejecutado por el procesador de consultas recibe su propio plan optimizado, que luego se almacena en el "Plan Caché" (Esto es por qué cambiaron el nombre de "Procedimiento-Caché")

Así que la bifurcación de su T-SQL en sentencias separadas es mejor ...

1

Reemplace el procedimiento almacenado individual por dos. Hay mucho espacio para que el optimizador de consultas comience a golpearlo con consecuencias imprevistas en este caso. Cambie el código del cliente para detectar a cuál llamar.

apuesto si se hubiera hecho de esa manera, no tendríamos que estar teniendo este diálogo.

Y poner un índice en ID de usuario. Los índices están ahí por una razón, y esto es todo.

Cuestiones relacionadas