La ricerca full-text risulta in una grande quantità di tempo impiegato nell'inizializzazione FULLTEXT


12

Attualmente sto cercando di eseguire alcune query su un dump di dati dei commenti di Stack Overflow. Ecco come appare lo schema:

CREATE TABLE `socomments` (
  `Id` int(11) NOT NULL,
  `PostId` int(11) NOT NULL,
  `Score` int(11) DEFAULT NULL,
  `Text` varchar(600) NOT NULL,
  `CreationDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `UserId` int(11) NOT NULL,
  PRIMARY KEY (`Id`),
  KEY `idx_socomments_PostId` (`PostId`),
  KEY `CreationDate` (`CreationDate`),
  FULLTEXT KEY `Text` (`Text`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Ho eseguito questa query sul tavolo e ha funzionato incredibilmente lentamente (ha 29 milioni di righe, ma ha un indice full-text):

SELECT *
FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)

Quindi l'ho profilato, i cui risultati sono:

|| Status                     || Duration ||
|| starting                   || 0.000058 ||
|| checking permissions       || 0.000006 ||
|| Opening tables             || 0.000014 ||
|| init                       || 0.000019 ||
|| System lock                || 0.000006 ||
|| optimizing                 || 0.000007 ||
|| statistics                 || 0.000013 ||
|| preparing                  || 0.000005 ||
|| FULLTEXT initialization    || 207.1112 ||
|| executing                  || 0.000009 ||
|| Sending data               || 0.000856 ||
|| end                        || 0.000004 ||
|| query end                  || 0.000004 ||
|| closing tables             || 0.000006 ||
|| freeing items              || 0.000059 ||
|| logging slow query         || 0.000037 ||
|| cleaning up                || 0.000046 ||

Come puoi vedere, trascorre molto tempo nell'inizializzazione FULLTEXT. È normale? In caso contrario, come lo riparerei?


Idea: crea una seconda tabella in cui inserisci ogni 1.000 commenti in un campo di testo. Ora cerchi inizialmente in questa seconda tabella e ottieni ad esempio id_group 2e id_group 23. Con questo la tua ricerca all'interno della tabella principale e limita la tua query agli intervalli di ID da 2.000 a 2.999 e da 23.000 a 23.999. Ovviamente il secondo otterrà più risultati se necessario mescolando tutti i commenti creando nuove combinazioni di parole chiave, ma alla fine dovrebbe accelerare il tutto. Ovviamente raddoppia l'utilizzo dello spazio su disco. I nuovi commenti dovrebbero essere CONCAT'di tabella del gruppo.
mgutt,

Risposte:


5

Altri hanno trovato questa situazione problematica

Poiché la documentazione di MySQL è molto concisa su questo stato del thread

Inizializzazione FULLTEXT

Il server si sta preparando per eseguire una ricerca full-text in linguaggio naturale.

l'unica soluzione sarebbe quella di prepararti con meno dati. Come ?

SUGGERIMENTO # 1

Guarda di nuovo la tua domanda. Sta selezionando tutte le colonne. Rifiuterei la query per raccogliere solo le colonne ID socomments. Quindi, unisci gli ID recuperati al socommentstavolo.

SELECT B.* FROM
(SELECT id FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)) A
LEFT JOIN socomments B USING (id);

Questo potrebbe produrre un piano EXPLAIN più brutto, ma penso che la profilazione cambierà in meglio. L'idea di base è: se si dispone di una ricerca FULLTEXT aggressiva, fare in modo che raccolga il minor numero di dati durante quella FULLTEXT initializationfase, riducendo così i tempi.

L'ho consigliato molte volte prima

SUGGERIMENTO # 2

Assicurati di impostare le opzioni FULLTEXT basate su InnoDB, non quelle per MyISAM. Le due opzioni che dovresti preoccupare sono

Pensaci un momento. Il campo di testo è VARCHAR (600). Supponiamo che la media sia di 300 byte. Ne hai 29.000.000 di milioni. Sarebbe un po 'di 8 GB. Forse aumentare anche innodb_ft_cache_size e innodb_ft_total_cache_size può anche aiutare.

Assicurarsi di disporre di RAM sufficiente per buffer InnoDB FULLTEXT più grandi.

PROVACI !!!


Ho provato entrambi i suggerimenti, abbattendo il tempo di circa 10 secondi, a 200 secondi. La cosa strana è che il pool di buffer è solo al 9% di utilizzo ...
hichris123,

Prova a mettere un segno più all'interno della parte CONTRO: SELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);e vedi se fa la differenza.
RolandoMySQLDBA il

Il motivo per cui ho suggerito un segno più? Doc ( dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html ) dice A leading or trailing plus sign indicates that this word must be present in each row that is returned. InnoDB only supports leading plus signs.Nel tuo caso particolare, fixed the postdeve esistere la frase esatta .
RolandoMySQLDBA,

Stessi risultati Un po 'più veloce e più lento, quindi probabilmente solo a causa di piccole differenze nel momento in cui è stato eseguito.
hichris123,

5

Se si utilizzano gli indici FULLTEXT di InnoDB, le query si bloccheranno spesso nello stato "Inizializzazione FULLTEXT" se si esegue una query su una tabella con un numero elevato di righe eliminate. Nell'implementazione FULLTEXT di InnoDB, le righe eliminate non vengono eliminate fino a quando non viene eseguita una successiva operazione OPTIMIZE sulla tabella interessata. Vedi: https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html

Per rimuovere le voci dell'indice full-text per i record eliminati, è necessario eseguire OPTIMIZE TABLE sulla tabella indicizzata con innodb_optimize_fulltext_only = ON per ricostruire l'indice full-text.

Si può anche ispezionare il numero di record eliminati ma non eliminati eseguendo una query in information_schema.innodb_ft_deleted

Per risolvere questo, si dovrebbe eseguire regolarmente OPTIMIZE TABLE su tabelle con indici InnoDB FULLTEXT.


Ottengo la logica su questo, ma puoi verificarlo innodb_optimize_fulltext_only=1e una OPTIMIZEtabella si occupa effettivamente delle righe eliminate "in attesa"? dba.stackexchange.com/questions/174486/…
Riedsio


0

Gli indici full-text in MySQL non sono progettati per supportare grandi quantità di dati, quindi la velocità di ricerca diminuisce abbastanza rapidamente mentre il set di dati sta crescendo. Una delle soluzioni consiste nell'utilizzare motori di ricerca full-text esterni come Solr o Sphinx che ha migliorato la funzionalità di ricerca (ottimizzazione della pertinenza e supporto per la ricerca di frasi, sfaccettature incorporate, frammenti, ecc.) Sintassi delle query estesa e velocità molto più elevata da metà a -grande serie di dati.

Solr si basa sulla piattaforma Java, quindi se si esegue un'applicazione basata su Java sarà la scelta naturale per te, Sphinx è scritto su C ++ e agisce come un demone allo stesso modo di MySQL. Non appena si alimenta il motore esterno con i dati che si desidera cercare, è anche possibile spostare alcune query da MySQL. Non posso dirti quale motore sia migliore nel tuo caso, uso principalmente Sphinx e qui è un esempio di utilizzo: http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

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.