La búsqueda de texto completo da como resultado una gran cantidad de tiempo dedicado a la "inicialización de FULLTEXT"

12

Actualmente estoy tratando de ejecutar algunas consultas contra un volcado de datos de los comentarios de Stack Overflow. Así es como se ve el esquema:

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

Ejecuté esta consulta en la tabla, y funcionó increíblemente lento (tiene 29 millones de filas, pero tiene un índice de texto completo):

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

Así que lo perfilé, cuyos resultados son:

|| 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 ||

Como puede ver, pasa mucho tiempo en la inicialización de FULLTEXT. ¿Esto es normal? Si no, ¿cómo lo arreglaría?

hichris123
fuente
Idea: Cree una segunda tabla donde coloque cada 1.000 comentarios en un campo de texto. Ahora busca al principio en esta segunda tabla y obtiene, por ejemplo, id_group 2y id_group 23. Con esto, su búsqueda dentro de su tabla principal y limitar su consulta a los rangos de identificación 2.000 a 2.999 y 23.000 a 23.999. Por supuesto, el segundo obtendrá más resultados según sea necesario a medida que mezcle todos los comentarios creando nuevas combinaciones de palabras clave, pero finalmente debería acelerar todo. Por supuesto, duplica el uso de espacio en disco. Los nuevos comentarios deben CONCATARSE a la tabla de grupo.
mgutt

Respuestas:

5

Otros han encontrado esto como una situación problemática.

Dado que la documentación de MySQL es muy breve en este estado de subproceso

Inicialización FULLTEXT

El servidor se está preparando para realizar una búsqueda de texto completo en lenguaje natural.

su único recurso sería hacer una preparación con menos datos. Cómo ?

SUGERENCIA # 1

Mire su consulta nuevamente. Está seleccionando todas las columnas. Refactorizaría la consulta para recopilar solo las columnas de identificación socomments. Luego, une esos identificadores recuperados a la socommentsmesa.

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

Esto podría producir un plan EXPLICAR más feo, pero creo que el perfil cambiará para mejor. La idea básica es: si tiene una búsqueda FULLTEXT agresiva, haga que recopile la menor cantidad de datos durante esa FULLTEXT initializationfase, reduciendo así el tiempo.

Lo he recomendado muchas veces antes

SUGERENCIA # 2

Asegúrese de configurar las opciones FULLTEXT basadas en InnoDB, no las de MyISAM. Las dos opciones que debe preocupar son

Piensa un momento en ello. El campo de texto es VARCHAR (600). Digamos que el promedio es de 300 bytes. Tienes 29,000,000 millones de ellos. Eso sería un poco de 8GB. Tal vez aumentar innodb_ft_cache_size e innodb_ft_total_cache_size también puede ayudar.

Asegúrese de tener suficiente RAM para los búferes InnoDB FULLTEXT más grandes.

DARLE UNA OPORTUNIDAD !!!

RolandoMySQLDBA
fuente
Intenté ambas sugerencias, redujo el tiempo alrededor de 10 segundos, a 200 segundos. Lo extraño es que el grupo de búferes es sólo a 9% de utilización ...
hichris123
Intente poner un signo más dentro de la parte CONTRA: SELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);y vea si hace la diferencia.
RolandoMySQLDBA
¿La razón por la que sugerí un signo más? 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.En su caso particular, fixed the postdebe existir la frase exacta .
RolandoMySQLDBA
Los mismos resultados Poco más rápido y más lento, por lo que probablemente solo se deba a pequeñas diferencias en el momento en que se ejecutó.
hichris123
5

Si está utilizando índices InnoDB FULLTEXT, las consultas a menudo se bloquean en el estado "Inicialización FULLTEXT" si está consultando una tabla que tiene una gran cantidad de filas eliminadas. En la implementación FULLTEXT de InnoDB, las filas eliminadas no se eliminan hasta que se ejecuta una operación OPTIMIZE posterior contra la tabla afectada. Ver: https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html

Para eliminar entradas de índice de texto completo para registros eliminados, debe ejecutar OPTIMIZE TABLE en la tabla indexada con innodb_optimize_fulltext_only = ON para reconstruir el índice de texto completo.

También se puede inspeccionar el número de registros eliminados pero no purgados al consultar information_schema.innodb_ft_deleted

Para resolver esto, regularmente se debe ejecutar OPTIMIZE TABLE en tablas con índices InnoDB FULLTEXT.

Tyler
fuente
Entiendo la lógica de esto, pero ¿puede verificar eso innodb_optimize_fulltext_only=1y una OPTIMIZEtabla realmente se encarga de las filas eliminadas "en espera"? dba.stackexchange.com/questions/174486/…
Riedsio
0

Los índices de texto completo en MySQL no están diseñados para admitir grandes cantidades de datos, por lo que la velocidad de búsqueda desciende bastante rápido a medida que crece su conjunto de datos. Una de las soluciones es utilizar motores de búsqueda externos de texto completo como Solr o Sphinx, que ha mejorado la funcionalidad de búsqueda (ajuste de relevancia y soporte de búsqueda de frases, facetas integradas, fragmentos, etc.) sintaxis de consulta extendida y una velocidad mucho más rápida en la mitad de -grandes conjuntos de datos.

Solr se basa en la plataforma Java, por lo que si ejecuta una aplicación basada en Java será una elección natural para usted, Sphinx está escrito en C ++ y actúa como un demonio de la misma manera que MySQL. Tan pronto como alimente a un motor externo con los datos que desea buscar, también puede mover algunas consultas fuera de MySQL. No puedo decirte qué motor es mejor en tu caso, utilizo principalmente Sphinx y aquí hay un ejemplo de uso: http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

vfedorkov
fuente