Il modo migliore per verificare se esiste una riga in una tabella MySQL


337

Sto cercando di scoprire se esiste una riga in una tabella. Utilizzando MySQL, è meglio fare una query come questa:

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

e controlla se il totale è diverso da zero o è meglio fare una query come questa:

SELECT * FROM table1 WHERE ... LIMIT 1

e verificare se sono state restituite righe?

In entrambe le query, la clausola WHERE utilizza un indice.

Risposte:


470

Puoi anche provare EXISTS:

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

e secondo la documentazione , puoi fare SELECTqualsiasi cosa.

Tradizionalmente, una sottoquery EXISTS inizia con SELECT *, ma potrebbe iniziare con SELECT 5 o SELECT column1 o altro. MySQL ignora l'elenco SELECT in tale subquery, quindi non fa alcuna differenza.


30
Prova con ...EXISTS( SELECT 1/0 FROM someothertable). Per SQL Server e Oracle - non fa alcuna differenza usare *, 1 o NULL perché EXISTS verifica solo un valore booleano basato su 1+ dei criteri WHERE corrispondenti.
OMG Pony

77
Ragazzi, si dice proprio nella documentazione collegata in questa risposta, secondo paragrafo, "Tradizionalmente, una sottoquery EXISTS inizia con SELECT *, ma potrebbe iniziare con SELECT 5 o SELECT column1 o altro. MySQL ignora l'elenco SELECT in tali una sottoquery, quindi non fa alcuna differenza ".
Aprire l'

12
@ChrisThompson: cosa succede quando viene eseguita la dichiarazione? Voglio dire cosa contiene il set di risultati?
Ashwin,

13
@Ashwin, contiene se 0 (non esiste) o 1 (esiste).
fedorqui "SO smettere di danneggiare"

10
Penso che la tua query sia superflua, ho testato e questa query SELECT 1 FROM table1 WHERE col = $var LIMIT 1è più veloce della tua query. Quindi qual è il vantaggio della tua query?
Shafizadeh,

182

Ho fatto alcune ricerche su questo argomento di recente. Il modo di implementarlo deve essere diverso se il campo è un campo TESTO, un campo non univoco.

Ho effettuato alcuni test con un campo TEXT. Considerando il fatto che abbiamo una tabella con voci 1M. 37 voci equivalgono a "qualcosa":

  • SELECT * FROM test WHERE texte LIKE '%something%' LIMIT 1con mysql_num_rows() : 0,039061069488525s. (PIÙ VELOCE)
  • 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.

Ma ora, con un campo BIGINT PK, solo una voce è uguale 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. (PIÙ VELOCE)

2
Grazie per la risposta aggiuntiva Hai trovato la differenza nel tempo tra le due opzioni più veloci per un campo TEXT essere abbastanza coerente? La differenza non sembra grande e l'utilizzo di SELECT EXISTS (SELECT 1 ... LIMIT 1) sembra essere abbastanza buono in entrambi i casi.
Bernard Chen,

1
Hai ragione, la differenza non è così importante per quanto riguarda gli altri risultati riguardanti il ​​campo di testo. Tuttavia, forse la query sarebbe meglio usareSELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
Laurent W.

Ho provato su mysql e nel caso in cui si usi select 1 ... limit 1, è inutile circondarsi di selezionare esiste
Adrien Horgnies,

4
@LittleNooby c'è differenza. SELECT EXISTS ... dà il valore vero e falso (1 o 0), mentre SELECT 1 ... dà 1 o vuoto. Esistono sottili differenze tra valore falso e set vuoto, a seconda della situazione.
Quickpick,

@LittleNooby fa un punto eccellente, che è facile da trascurare. Mancare nei test di cronometraggio sopra è SELECT 1 FROM test WHERE ..., senza SELECT EXISTSaggirarlo. Presumibilmente è un pelo più veloce in quel modo.
ToolmakerSteve

27

Un breve esempio della risposta di @ ChrisThompson

Esempio:

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)

Utilizzando un alias:

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

18

Nella mia ricerca, trovo che il risultato vada avanti seguendo la velocità.

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) 

12

Sento che vale la pena sottolineare, sebbene sia stato toccato nei commenti, che in questa situazione:

SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1

È superiore a:

SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1

Questo perché la prima query può essere soddisfatta dall'indice, mentre la seconda richiede una ricerca di righe (a meno che possibilmente tutte le colonne della tabella non siano nell'indice utilizzato).

L'aggiunta della LIMITclausola consente al motore di arrestarsi dopo aver trovato una riga.

La prima query dovrebbe essere paragonabile a:

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

Che invia gli stessi segnali al motore (1 / * non fa alcuna differenza qui), ma scrivo comunque 1 per rinforzare l'abitudine quando uso EXISTS:

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

Potrebbe essere utile aggiungere il EXISTSwrapping se è necessario un ritorno esplicito quando nessuna riga corrisponde.


4

Ti suggerisco di non usare Countperché count fa sempre carichi extra per l'uso di db SELECT 1e restituisce 1 se il tuo record è lì, altrimenti restituisce null e puoi gestirlo.


2

Una COUNT query è più veloce, anche se forse non in modo evidente, ma per quanto riguarda il raggiungimento del risultato desiderato, entrambi dovrebbero essere sufficienti.


4
Questo è tuttavia specifico per DB. Il COUNT (*) è noto per essere lento in PostgreSQL. Meglio sarebbe selezionare la colonna PK e vedere se restituisce delle righe.
BalusC

3
COUNT (*) è lento in InnoDB però
Will

2

A volte è abbastanza utile ottenere la chiave primaria ( id) di incremento automatico della riga se esiste e in 0caso contrario.

Ecco come è possibile farlo in una singola query:

SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...

Perché non usare solo IFNULL(id, 0)qui invece di COUNT(*)?
Ethan Hohensee,


-1

Vorrei andare con COUNT(1). È più veloce COUNT(*)perché COUNT(*)test per vedere se almeno una colonna in quella riga è! = NULL. Non ne hai bisogno, soprattutto perché hai già una condizione (la WHEREclausola). COUNT(1)verifica invece la validità di 1, che è sempre valida e richiede molto meno tempo per testare.


8
-1 Questo è sbagliato. COUNT (*) non esamina i valori della colonna, ma solo il numero di righe. Vedi la mia risposta qui: stackoverflow.com/questions/2876909/…
Mark Byers,

6
COUNT () è molto più lento di EXISTS in quanto EXISTS può tornare quando trova per la prima volta una riga
Will

-1

Oppure puoi inserire la parte sql non elaborata nelle condizioni in modo che io abbia "condizioni" => array ("Member.id NON IN (SELEZIONA Membership.member_id DA appartenenze COME Iscrizione)")


-2

COUNT(*) sono ottimizzati in MySQL, quindi la prima query sarà probabilmente più veloce, in generale.


2
Ti riferisci all'ottimizzazione di MyISAM per la selezione del conteggio per un'intera tabella? Non pensavo che sarebbe stato d'aiuto se ci fosse una condizione WHERE.
Bernard Chen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.