2009-11-10 11 views
19

Me gustaría escribir una consulta que simplemente devuelve 1 o 0, dependiendo de si habrá resultados.Manera eficiente de comprobar si una consulta SQL arrojará los resultados

Me refiero a utilizar este

IF EXISTS(
     select * from myTable 
     where id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE() 
) 
SELECT 1 
ELSE 
SELECT 0 

Esa es la premisa general.

Los resultados finales serán en realidad una consulta mucho más compleja, teniendo uno de muchos parámetros y la cadena construido y ejecutado utilizando sp_executesql

Mi pregunta es digamos el 'recuento' devolvería 376.986 y toma 4 segundos calcular. El uso de IF EXISTS se detendrá tan pronto como encuentre 1 fila que satisfaga los criterios.

Estoy decidiendo si utilizar EXISTS o simplemente consultar el @@ ROWCOUNT y ver si es mayor que cero.

Probé algunas pruebas y ambas funcioné casi a la misma velocidad, pero en 2 años cuando hay muchos más datos, ¿es probable que usar IF EXISTS sea una ganancia de rendimiento o no?

Gracias

Respuesta

7

IF EXISTS debería ser más eficiente, porque está optimizado para detenerse tan pronto como encuentre la primera fila. Así es como siempre haría este tipo de control, sin usar un COUNT().

Para la comparación de rendimiento, simplemente asegurarse de que está probando bastante en la limpieza de abajo de la de datos y ejecución del plan de cachés (servidor db no sea de producción solamente) antes de cada prueba:

DBCC FREEPROCCACHE 
DBCC DROPCLEANBUFFERS 
+0

Esto depende del optimizador de consultas del DBMS. Si sus pruebas muestran que lleva 4 segundos con IF EXISTS y COUNT, entonces IF EXISTS probablemente no está optimizado. –

+0

Por ahora los resultados son los mismos, pero estaba preguntando más por el futuro. A medida que aumentaba el número de filas, me preguntaba si el rendimiento del recuento sería más lento. Alguien sugirió que no lo haría, ya que las tablas se analizan y el recuento de actuaciones sigue siendo bastante rápido de todos modos. Estoy tendiendo hacia el IF EXISTE más y más. – Robert

+0

Compararía ambos, con caché limpia, comprobación de duración, CPU y lecturas a través del Analizador de SQL, y esperaría que EXISTS no solo se desempeñara mejor en SQL Server, sino que también escalara mejor cuando crecieran los volúmenes de datos. Con pequeñas cantidades de datos, no habrá mucha diferencia, pero la escalabilidad es importante. – AdaTheDev

11

¿Tiene un índice de identificación y fecha?

tal vez sólo quiere:

select top 1 1 from myTable where id=7 and rowInsertDate > '01/01/2009' 

nota: esto sería volver 1 si existen datos, o nada de otra manera.

otra edición. Esto no devolverá una fila con el valor nulo si no hay datos, sino que no devolverá ninguna fila. Más como nulo en su sentido más figurativo.

+0

Esto da una pista mucho mayor al optimizador de consultas y espero que sea mucho más rápido. –

+0

Inteligente = solución. –

+0

asegúrese de obtener la cláusula límite dependiente de la plataforma apropiada .. top 1 o limit 1, etc. – Kevin

2

Si no es necesario 376986 filas y solo quiero saber si existe algo, entonces SI EXISTE tiene mucho más sentido. Además, otro poco útil es pedir una columna indexada (clave principal) en lugar de * porque no le importan los datos reales.

+0

Gracias, me aseguraré de pedir solo una columna en mis resultados ya que en realidad no quiero los resultados. – Robert

10

Este es el más rápido que pude conseguir en mis proyectos:

SELECT CASE WHEN EXISTS (
    select top 1 1 
    from myTable 
    where id=7 
    and rowInsertDate BETWEEN '01/01/2009' AND GETDATE() 
) THEN 1 ELSE 0 END AS AnyData 
+0

Esta es la premisa general que voy a utilizar. Gracias – Robert

0

En primer lugar, usted debe tratar al muerto una base de datos que contiene todos los datos que usted piensa que usted (o sus sucesores) podría tener que hacer frente dentro de dos años. Entonces tus pruebas serán mucho más productivas.

IF EXISTS() será más rápido, ya que el motor de la base de datos solo tiene que encontrar un primer registro que coincida con sus criterios. Por supuesto, será más rápido aún con los índices adecuados.

Otra sugerencia, no use *, ya que en realidad no necesita recuperar columnas.

IF EXISTS(select 1 from myTable where id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE()) 

... debería (por lo que he leído) trabajar un poco más rápido.

+1

No importa si usa SELECT * ... EXISTS está optimizado para eso. No hace ninguna diferencia. – AdaTheDev

2

me acaba de escribir de esta manera:

IF EXISTS(
     SELECT 0 FROM myTable 
     WHERE id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE() 
) 
SELECT 1 
ELSE 
SELECT 0 

De esa manera usted no devuelve ningún dato sólo comprueban condiciones. Encuentro esta estructura de consulta muy rápida.

1

Los resultados finales serán en realidad una consulta mucho más compleja, teniendo uno a muchos parámetros y la cadena construida y ejecutada utilizando sp_executesql

Creo que, al menos, necesita el sintaxis completa FROM, JOIN y WHERE; de lo contrario, su consulta real puede encontrar información (por ejemplo, agregando un INNER JOIN que no estaba en la consulta original IF EXISTS y resulta que no está satisfecho).

Si va a tener ese problema, es posible que desee obtener los PK en una especie de "Tabla de retención de ID de lote" para que pueda simplemente hacer referencia a los PK para la segunda parte de "Presentación" de su consulta.

¿Qué piensas hacer si obtienes 376,986 resultados? Si se los va a mostrar al usuario en la pantalla, con algún tipo de paginación, entonces tener los resultados en una "Tabla de retención de ID de lote" podría ayudar con eso (aunque, obviamente, cualquier adición/eliminación, etc. a los datos de usuario) ensuciará la pantalla paginada).

Alternativamente, si va a utilizar paginación solo use TOP/LIMIT/SET ROWCOUNT para restringir los resultados a la primera página llena (asegúrese de tener un ORDER BY para que la secuencia sea repetible), y luego resuelva qué hacer para la página 2 cuando el usuario presiona el botón NEXT-PAGE (abordamos eso con el botón NEXT-PAGE que contiene la PK del último registro visualizado, en orden de clasificación, para que la página siguiente pueda reanudarse desde ese punto en adelante))

El Optimizador de consultas hará diferentes cosas dependiendo de la lista SELECT, por lo que preguntar "SI EXISTE" seguido de "SELECCIONAR Col1, COl2, ... DESDE ..." puede significar que ejecuta el completo consulta dos veces, de manera diferente, utilizando diferentes datos almacenados en caché y planes de consulta, por lo que en general puede suponer una mayor tensión para el servidor y hacer que los usuarios esperen más tiempo que solo obtener la primera página/100 filas, etc.

SQL El servidor guardará en caché el plan de consulta para sp_ExecuteSQL, pero asegúrese de parametrizar la consulta para que el plan guardado en caché se reevalúe siempre que sea posible

+0

Sí, definitivamente voy a paramaterizar la consulta generada y pasar mis parámetros a sp_executesql. Recuerdo la primera vez que vi que tenía que reír. Ahora estoy bastante bien con eso :) – Robert

0

Creo que la respuesta de Alex Bagnolini es correcta. El sistema no me dejaba comentar su respuesta (nuevo acct). La única modificación que haría es cambiar el segundo 1 a id.

A veces la reducción de la lista en la sección del proyecto (esa es la lista de columnas) permite que el motor de db llegue solo al índice y no a la tabla, por lo tanto más rápido. Esto depende de su motor de DB, y de la estructura/tamaño del índice, por supuesto.(Todas las fechas rowInsertDate deben ser < getDate(), por lo que puede saltar esa comparación)

SELECT CASE CUANDO EXISTE ( seleccione la parte superior 1 Identificación del de myTable donde id = 7 y rowInsertDate> '01/01/2009 ' ) ENTONCES 1 ELSE 0 END COMO AnyData

Cuestiones relacionadas