La query di selezione richiede più tempo di quanto dovrebbe


9

Ho una tabella di database MySQL con quasi 23 milioni di record. Questa tabella non ha una chiave primaria, perché nulla è unico. Ha 2 colonne, entrambe sono indicizzate. Di seguito è la sua struttura:

inserisci qui la descrizione dell'immagine

Di seguito alcuni dei suoi dati:

inserisci qui la descrizione dell'immagine

Ora ho eseguito una semplice query:

SELECT `indexVal` FROM `key_word` WHERE `hashed_word`='001'

Purtroppo, sono stati necessari più di 5 secondi per recuperare i dati e mostrarmeli. La mia futura tabella avrà 150 miliardi di record, quindi questa volta è molto alta.

Ho eseguito il Explaincomando per vedere cosa sta succedendo. Il risultato è sotto.

inserisci qui la descrizione dell'immagine

Quindi ho eseguito il profilo usando il comando seguente.

SET profiling=1;
SELECT `indexVal` FROM `key_word` WHERE `hashed_word` = '001';
SHOW profile;

Di seguito è riportato il risultato della profilazione:

inserisci qui la descrizione dell'immagine

Di seguito alcune ulteriori informazioni sulla mia tabella:

inserisci qui la descrizione dell'immagine

Quindi, perché ci vuole così tanto tempo? Sono anche indicizzati! In futuro, dovrò eseguire molti LIKEcomandi, quindi ci vuole troppo tempo. Cosa è andato storto?


"Questa tabella non ha una chiave primaria, perché nulla è unico." Sì, giusto ... È ora di riesaminare il tuo progetto. Tutte le tabelle dovrebbero avere una chiave primaria (o unica).
ypercubeᵀᴹ

Risposte:


10

Hai chiesto " perché questo impiega troppo tempo ?". Hai anche detto " Sfortunatamente, sono stati necessari più di 5 secondi per recuperare i dati e mostrarmeli ". Inoltre, hai segnalato l'output di profilazione della tua query.

Come puoi vedere te stesso, la somma dei tempi riportati dal profiler per ogni passaggio conta 0,000154 secondi. Quindi, dal punto di vista del profiler, la query è stata completata in un tempo simile (0,000154).

Quindi perché stai ottenendo risultati in " ... più di 5 secondi? ".

Hai detto che stai filtrando una tabella record di 23 milioni con un campo di 3 caratteri. Sfortunatamente non ci dici quanti record restituisce la tua query ... ma grazie a EXPLAIN SELECT fornito, sembra che la tua query abbia restituito 336052 record.

Sembra, inoltre, che tutta la tua attività passi attraverso una GUI (PHPMyAdmin?).

Quindi, dopo tutto quanto sopra, possiamo riformulare la tua domanda originale come:

"Perché nella mia GUI vengono visualizzati i record 336.052 visualizzati in più di 5 secondi, se il tempo di esecuzione di MySQL per la query correlata è 0,000154 secondi?"

La risposta, secondo me, è abbastanza semplice: 5 secondi è il tempo (davvero basso, in effetti) per lasciare che i record 336.052 viaggino lungo il percorso: motore MySQL => librerie client MySQL => modulo MySQL PHP => Apache => Network = > PC TCP / IP stack => Browser => DOM parser / builder / ecc. => Pagina HTML renderizzata.

Per quanto riguarda la mia precedente esperienza, il tempo richiesto dalla trasmissione dei risultati è "normalmente" molto più lungo del tempo necessario per recuperare tali dati. Ciò è particolarmente vero quando sono coinvolte librerie come PHP-MySQL o Perl-DBD-MySQL: richiedono davvero molto tempo per recuperare i record, dopo che MySQL li ha identificati (... ed estratti) correttamente.

Come risolvere questo problema?

Ancora una volta, abbastanza facilmente: sei davvero sicuro di aver bisogno di TUTTO il record 336.052, in un singolo set di dati completo?

  • Se la tua risposta è davvero "SÌ! Ho bisogno di tutti loro", la tua applicazione gestirà PAGINATION e / o USER-Interaction da sola e ... una volta raccolti tutti questi dati, probabilmente impiegherà molto tempo interagire con l'utente senza richiedere ulteriori interazioni MySQL. In tal caso, attendere 5 secondi (o anche di più) non dovrebbe essere un problema;

  • Se la tua risposta è "NO, voglio occuparmi di una dimensione del set di dati più" umana "", di quanto devi perfezionare la tua query (almeno) in modo che ti restituisca un set di dati più "umano" (decine o, centinaia, al massimo, record). In tal caso, scommetto che otterrai il tuo risultato in un tempo più breve.


A proposito: questo è esattamente lo stesso problema che hai riscontrato in questo altro post , su ServerFault: 88 secondi per consentire ai record 132M di viaggiare lungo il percorso magico .... non-mysql-strettamente correlato :-)


Mi aspetto una risposta dall'op.
Jnanaranjan,

5
  1. Controlla mysql innodb_buffer_pool_size . Dovrebbe essere abbastanza grande: più è, meglio è. Ma non troppo per evitare lo scambio del sistema operativo.

    show variables like 'innodb_buffer_pool_size'

    mostrerà la dimensione del buffer in byte.

  2. Controlla la query più di una volta. La prima esecuzione potrebbe essere troppo lunga poiché i dati devono essere letti dal disco nella memoria. Quando si esegue la query per la prima volta, i dati non si trovano ancora nel buffer innodb e devono essere letti dal disco. Il che è molto più lento che se i dati fossero già nella cache. Quindi esegui la query un paio di volte per assicurarti che venga pubblicata dalla cache.

  3. Disabilitare la cache delle query poiché ogni esecuzione conseguente sarà soddisfatta da essa e influenzerà i risultati del test. C'è un meccanismo in MySQL, chiamato "query cache" che è progettato per archiviare le query insieme ai loro risultati. Pertanto, la seconda volta che viene richiesto a MySQL di eseguire la query, è possibile ignorare l'esecuzione e recuperare i risultati dalla cache della query.

  4. Prendi in considerazione l'utilizzo di un "indice di copertura":

    ALTER TABLE key_word ADD KEY IX_hashed_word_indexVal (hashed_word, indexVal);

Questo sarebbe molto più efficiente, da allora MySQL può soddisfare la richiesta di query solo dall'indice.

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.