La mejor manera de probar si existe una fila en una tabla MySQL

337

Estoy tratando de averiguar si existe una fila en una tabla. Usando MySQL, ¿es mejor hacer una consulta como esta?

SELECT COUNT(*) AS total FROM table1 WHERE ...

y verifique si el total no es cero o es mejor hacer una consulta como esta:

SELECT * FROM table1 WHERE ... LIMIT 1

y verifica si alguna fila fue devuelta?

En ambas consultas, la cláusula WHERE usa un índice.

Bernard Chen
fuente

Respuestas:

470

También puedes probar EXISTS:

SELECT EXISTS(SELECT * FROM table1 WHERE ...)

y según la documentación , puedes SELECTcualquier cosa.

Tradicionalmente, una subconsulta EXISTA comienza con SELECT *, pero podría comenzar con SELECT 5 o SELECT column1 o cualquier cosa. MySQL ignora la lista SELECT en dicha subconsulta, por lo que no hay diferencia.

Chris Thompson
fuente
30
Prueba con ...EXISTS( SELECT 1/0 FROM someothertable). Para SQL Server y Oracle: no hace ninguna diferencia usar *, 1 o NULL porque EXISTS solo prueba un valor booleano basado en 1+ de la coincidencia de criterios WHERE.
OMG Ponis
77
Chicos, dice justo en la documentación vinculada a esta respuesta, segundo párrafo, "Tradicionalmente, una subconsulta EXISTA comienza con SELECT *, pero podría comenzar con SELECT 5 o SELECT column1 o cualquier cosa. MySQL ignora la lista SELECT en tal una subconsulta, por lo que no hay diferencia ".
mpen
12
@ChrisThompson: ¿qué sucede cuando se ejecuta la declaración? Quiero decir, ¿qué contiene el conjunto de resultados?
Ashwin el
13
@Ashwin, contiene si un 0 (no existe) o 1 (existe).
Fedorqui 'así que deja de dañar'
10
Creo que su consulta es superflua, probé, y esta consulta SELECT 1 FROM table1 WHERE col = $var LIMIT 1es más rápida que su consulta. Entonces, ¿cuál es la ventaja de su consulta?
Shafizadeh
182

He realizado algunas investigaciones sobre este tema recientemente. La forma de implementarlo debe ser diferente si el campo es un campo TEXTO, un campo no único.

He realizado algunas pruebas con un campo TEXTO. Considerando el hecho de que tenemos una tabla con 1M de entradas. 37 entradas son iguales a 'algo':

  • SELECT * FROM test WHERE texte LIKE '%something%' LIMIT 1con mysql_num_rows() : 0.039061069488525s. (MÁS RÁPIDO)
  • SELECT count(*) as count FROM test WHERE text LIKE '%something% : 16.028197050095s.
  • SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%') : 0.87045907974243s.
  • SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%' LIMIT 1) : 0.044898986816406s.

Pero ahora, con un campo BIGINT PK, solo una entrada es igual a '321321':

  • SELECT * FROM test2 WHERE id ='321321' LIMIT 1con mysql_num_rows() : 0.0089840888977051s.
  • SELECT count(*) as count FROM test2 WHERE id ='321321' : 0.00033879280090332s.
  • SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321') : 0.00023889541625977s.
  • SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321' LIMIT 1): 0.00020313262939453s. (MÁS RÁPIDO)
Laurent W.
fuente
2
Gracias por la respuesta adicional. ¿Encontró la diferencia en el tiempo entre las dos opciones más rápidas para que un campo TEXTO sea bastante consistente? La diferencia no parece grande, y usar SELECT EXISTS (SELECT 1 ... LIMIT 1) parece ser bastante bueno en ambos casos.
Bernard Chen
1
Tiene razón, la diferencia no es tan importante con respecto a los otros resultados relacionados con el campo de texto. Sin embargo, tal vez la consulta sería mejor usandoSELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
Laurent W.
Lo probé en mysql y, en el caso de que lo uses select 1 ... limit 1, es inútil rodearlo con select existe
Adrien Horgnies
44
@LittleNooby hay diferencia. SELECT EXISTS ... da el valor verdadero y falso (1 o 0), mientras que SELECT 1 ... da 1 o vacío. Hay una sutil diferencia entre el valor falso y el conjunto vacío, según su situación.
Quickpick
@LittleNooby hace un excelente punto, que es fácil pasar por alto. Falta en las pruebas de tiempo anteriores SELECT 1 FROM test WHERE ..., sin SELECT EXISTSrodeos. Presumiblemente es un cabello más rápido de esa manera.
ToolmakerSteve
27

Un breve ejemplo de la respuesta de @ ChrisThompson

Ejemplo:

mysql> SELECT * FROM table_1;
+----+--------+
| id | col1   |
+----+--------+
|  1 | foo    |
|  2 | bar    |
|  3 | foobar |
+----+--------+
3 rows in set (0.00 sec)

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 1) |
+--------------------------------------------+
|                                          1 |
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 9);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 9) |
+--------------------------------------------+
|                                          0 |
+--------------------------------------------+
1 row in set (0.00 sec)

Usando un alias:

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1) AS mycheck;
+---------+
| mycheck |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)
jaltek
fuente
18

En mi investigación, puedo encontrar el resultado en la siguiente velocidad.

select * from table where condition=value
(1 total, Query took 0.0052 sec)

select exists(select * from table where condition=value)
(1 total, Query took 0.0008 sec)

select count(*) from table where condition=value limit 1) 
(1 total, Query took 0.0007 sec)

select exists(select * from table where condition=value limit 1)
(1 total, Query took 0.0006 sec) 
shihab mm
fuente
12

Creo que vale la pena señalar, aunque se mencionó en los comentarios, que en esta situación:

SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1

Es superior a:

SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1

Esto se debe a que el índice puede satisfacer la primera consulta, mientras que la segunda requiere una búsqueda de fila (a menos que posiblemente todas las columnas de la tabla estén en el índice utilizado).

Agregar la LIMITcláusula permite que el motor se detenga después de encontrar cualquier fila.

La primera consulta debe ser comparable a:

SELECT EXISTS(SELECT * FROM my_table WHERE *indexed_condition*)

Lo que envía las mismas señales al motor (1 / * no hace ninguna diferencia aquí), pero aún escribiría el 1 para reforzar el hábito al usar EXISTS:

SELECT EXISTS(SELECT 1 FROM my_table WHERE *indexed_condition*)

Puede tener sentido agregar el EXISTSajuste si necesita un retorno explícito cuando no coinciden las filas.

Arth
fuente
4

Sugiero que no lo use Countporque count siempre hace cargas adicionales para el uso de db SELECT 1y devuelve 1 si su registro allí mismo, de lo contrario, devuelve nulo y puede manejarlo.

Fatih Karatana
fuente
2

Una consulta COUNT es más rápida, aunque tal vez no sea notable, pero en lo que respecta a obtener el resultado deseado, ambas deberían ser suficientes.

jaywon
fuente
44
Sin embargo, esto es específico de DB. Se sabe que COUNT (*) es lento en PostgreSQL. Mejor sería seleccionar la columna PK y ver si devuelve alguna fila.
BalusC el
3
Sin embargo
el
2

A veces es bastante útil obtener la clave primaria de incremento automático ( id) de la fila si existe y 0si no.

Así es como se puede hacer esto en una sola consulta:

SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...
Zaxter
fuente
¿Por qué no solo usar IFNULL(id, 0)aquí en lugar del COUNT(*)?
Ethan Hohensee
-1

Me gustaría ir con COUNT(1). Es más rápido que COUNT(*)porque las COUNT(*)pruebas para ver si al menos una columna en esa fila es! = NULL. No necesita eso, especialmente porque ya tiene una condición (la WHEREcláusula). COUNT(1)en cambio prueba la validez de 1, que siempre es válida y lleva mucho menos tiempo probarla.

Felix
fuente
8
-1 Esto está mal. COUNT (*) no mira los valores de las columnas, solo cuenta el número de filas. Vea mi respuesta aquí: stackoverflow.com/questions/2876909/…
Mark Byers
66
COUNT () es mucho más lento que EXISTS ya que EXISTS puede regresar cuando encuentra una fila por primera vez
el
-1

O puede insertar una parte sql sin procesar en las condiciones para que tenga 'condiciones' => array ('Member.id NOT IN (SELECCIONE Membership.member_id FROM membresías AS Membership)')

usuario4193303
fuente
-2

COUNT(*) están optimizados en MySQL, por lo que es probable que la consulta anterior sea más rápida, en general.

Arthur Reutenauer
fuente
2
¿Se refiere a la optimización que tiene MyISAM para seleccionar el recuento de una tabla completa? No pensé que eso ayudara si había una condición WHERE.
Bernard Chen el