2009-09-18 10 views
15

Ho una tabella di dimensioni modeste, 277k record al momento, che sto cercando di fare una ricerca su FULLTEXT. La ricerca sembra essere molto veloce fino a quando arriva alla fase di invio dei dati.MySQL "Invio di dati" orribilmente lento

La Tavola:

CREATE TABLE `sqinquiries_inquiry` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `ts` datetime NOT NULL, 
    `names` longtext NOT NULL, 
    `emails` longtext NOT NULL, 
    PRIMARY KEY (`id`), 
    FULLTEXT KEY `sqinquiries_inquiry_search` (`names`,`emails`) 
) ENGINE=MyISAM AUTO_INCREMENT=305560 DEFAULT CHARSET=latin1 

La Query:

SELECT * FROM `sqinquiries_inquiry` WHERE (
    MATCH (`sqinquiries_inquiry`.`names`) AGAINST ('smith' IN BOOLEAN MODE) OR 
    MATCH (`sqinquiries_inquiry`.`emails`) AGAINST ('smith' IN BOOLEAN MODE) 
) ORDER BY `sqinquiries_inquiry`.`id` DESC LIMIT 100 

Il profilo: (I stato tagliato fuori informazioni apparentemente inutile)

+-------------------------+----------+ 
| Status     | Duration | 
+-------------------------+----------+ 
| preparing    | 0.000014 | 
| FULLTEXT initialization | 0.000015 | 
| executing    | 0.000004 | 
| Sorting result   | 0.000008 | 
| Sending data   | 2.247934 | 
| end      | 0.000011 | 
| query end    | 0.000003 | 
+-------------------------+----------+ 

Il DESCRIBE sembra grande, un semplice rivestimento: la descrizione:

id: 1 
select_type: SIMPLE 
table: sqinquiries_inquiry 
type: index 
possible_keys: NULL 
key: PRIMARY 
key_len: 4 
ref: NULL 
rows: 100 
Extra: Using where 

Quindi quello che non capisco è dove i 2,25 secondi di invio dati sono provenienti da? Vedo prestazioni simili in Python e nella console mysql, entrambe collegate a localhost.

Aggiornamenti:

  • Per commento richiede la dimensione media di fila, si tratta di: 53,8485
  • Per commenti, qui è il DESCRIBE sopra.
+0

Quanto è grande la quantità di dati che stai recuperando? se non lo sai, guarda le statistiche della tabella e dicci la dimensione media della riga. – longneck

+0

Non ero sicuro di come calcolare la dimensione media della riga, quindi ho lanciato l'output di questo file: "SELEZIONA AVG (LENGTH (nomi) + LENGTH (email) + LENGTH (id) + LENGTH (ts)) come avg_length da sqinquiries_inquiry'. Se c'è un modo migliore, per favore fatemelo sapere. –

+0

Il problema è che il tuo 'FULLTEXT KEY' non è usato. Potresti per favore postare il 'DESCRIVERE'? – Quassnoi

risposta

32

Il DESCRIBE sembra grande, un semplice rivestimento.

Poiché si sta utilizzando solo una tabella nella query, non può essere altro che una riga singola.

Tuttavia, la query non utilizza l'indice FULLTEXT.

Per l'indice per essere utilizzabili, si dovrebbe riscrivere la query un po ':

SELECT * 
FROM sqinquiries_inquiry 
WHERE MATCH (names, emails) AGAINST ('smith' IN BOOLEAN MODE) 
ORDER BY 
     id DESC 
LIMIT 100 

MATCH utilizza solo l'indice se l'oggetto che partita contro l'esatto set di colonne dell'indice è definito in.

Quindi la query utilizza l'indice di scansione su id: Using index; Using where alla fine del proprio DESCRIBE.

Sending data è piuttosto fuorviante: questo è in realtà il tempo trascorso tra la fine dell'operazione precedente e la fine dell'operazione corrente.

Ad esempio, ho appena eseguito questa domanda:

SET profiling = 1; 

SELECT * 
FROM t_source 
WHERE id + 1 = 999999; 

SHOW PROFILE FOR QUERY 39; 

che restituito un'unica fila e questo profilo:

'starting', 0.000106 
'Opening tables', 0.000017 
'System lock', 0.000005 
'Table lock', 0.000014 
'init', 0.000033 
'optimizing', 0.000009 
'statistics', 0.000013 
'preparing', 0.000010 
'executing', 0.000003 
'Sending data', 0.126565 
'end', 0.000007 
'query end', 0.000004 
'freeing items', 0.000053 
'logging slow query', 0.000002 
'cleaning up', 0.000005 

Poiché l'indice non è utilizzabile, MySQL deve eseguire la tabella completa scansione.

0.126565 secondi sono il tempo dall'inizio dell'esecuzione (il tempo in cui è stata letta la prima riga) e la fine dell'esecuzione (il tempo in cui l'ultima riga è stata inviata al client).

Quest'ultima fila si trova all'estremità della tabella e ci è voluto molto tempo per trovarla e inviarla.

P. S. A cura di rimuovere il downvote :)

+0

Sto usando la versione 5.1.35. E perché l'indice non sarebbe utilizzabile? –

+0

'@Jack M.': il mio post spiega perché. – Quassnoi

+0

'@Jack M.': e potresti spiegare il tuo downvote? – Quassnoi

-8

Penso di trasferire molti dati un una connessione di rete lenta.

Invece di selezionare * selezionare solo le colonne di cui si ha realmente bisogno.

Se la tabella contiene campi di testo di grandi dimensioni che si desidera visualizzare nel risultato, è possibile utilizzare la sottostringa per trasferire solo i primi caratteri/parole del testo.

Alcuni client supportano la compressione dei pacchetti di risultati. Forse vuoi dare un'occhiata a questo.

+2

Questo è in esecuzione da localhost, restituendo solo 100 risultati e la maggior parte dei risultati sono 1 indirizzo email e un nome. Non grandi quantità di dati, non connessioni lente. –