Atualmente, estou tentando executar algumas consultas em um despejo de dados dos comentários do Stack Overflow. Aqui está a aparência do 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
Fiz essa consulta na tabela e ela ficou incrivelmente lenta (ela possui 29 milhões de linhas, mas possui um índice de texto completo):
SELECT *
FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)
Então eu criei um perfil, cujos resultados são:
|| 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 você pode ver, ele passa muito tempo na inicialização do FULLTEXT. Isso é normal? Se não, como eu consertaria isso?
mysql
innodb
full-text-search
hichris123
fonte
fonte
id_group 2
eid_group 23
. Com isso, sua pesquisa dentro da tabela principal e limita sua consulta aos intervalos de ID 2.000 a 2.999 e 23.000 a 23.999. É claro que o segundo resultará em mais resultados, conforme necessário, à medida que você mistura todos os comentários, criando novas combinações de palavras-chave, mas, finalmente, deve acelerar a coisa toda. É claro que duplica o uso do espaço em disco. Novos comentários devem ser CONCATADOS na tabela de grupo.Respostas:
Outros acharam esta uma situação problemática
Como a documentação do MySQL é muito concisa neste estado de thread
seu único recurso seria fazer a preparação com menos dados. Como ?
SUGESTÃO # 1
Olhe para sua consulta novamente. Está selecionando todas as colunas. Eu refatoraria a consulta para coletar apenas as colunas de identificação
socomments
. Em seguida, junte os IDs recuperados de volta àsocomments
tabela.Isso pode produzir um plano EXPLAIN mais feio, mas acho que os perfis mudarão para melhor. A idéia básica é: se você tem uma pesquisa FULLTEXT agressiva, faça com que ela colete a menor quantidade de dados durante essa
FULLTEXT initialization
fase, reduzindo assim o tempo.Eu recomendei isso muitas vezes antes
May 14, 2012
: consulta lenta com texto completo e junção esquerdaMar 18, 2012
: Por que LIKE é mais que 4x mais rápido que MATCH ... CONTRA em um índice FULLTEXT no MySQL?Jan 26, 2012
: Pesquisa de texto completo do Mysql otimização my.cnf :Oct 25, 2011
: Índice FULLTEXT ignorado no MODO BOOLEAN com 'número de palavras' condicionalSUGESTÃO # 2
Certifique-se de definir as opções FULLTEXT baseadas no InnoDB, não as do MyISAM. As duas opções que você deve se preocupar são
Pense nisso por um momento. O campo de texto é VARCHAR (600). Digamos que a média é de 300 bytes. Você tem 29.000.000 milhões deles. Isso seria um pouco de 8GB. Talvez aumentar innodb_ft_cache_size e innodb_ft_total_cache_size também possa ajudar.
Verifique se você possui RAM suficiente para buffers InnoDB FULLTEXT maiores.
DE UMA CHANCE !!!
fonte
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 veja se isso faz diferença.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.
No seu caso particular, a frase exatafixed the post
deve existir.Se você estiver usando os índices InnoDB FULLTEXT, as consultas geralmente serão interrompidas no estado "Inicialização FULLTEXT" se você estiver consultando uma tabela que possui um grande número de linhas excluídas. Na implementação FULLTEXT do InnoDB, as linhas excluídas não são removidas até que uma operação OPTIMIZE subsequente seja executada na tabela afetada. Consulte: https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html
Pode-se também inspecionar o número de registros excluídos, mas não eliminados, consultando information_schema.innodb_ft_deleted
Para resolver isso, deve-se executar regularmente OPTIMIZE TABLE em tabelas com índices InnoDB FULLTEXT.
fonte
innodb_optimize_fulltext_only=1
e umaOPTIMIZE
tabela realmente cuida das linhas excluídas "em espera"? dba.stackexchange.com/questions/174486/…Há um erro confirmado no MySQL ( DOCID excluído não é mantido durante as tabelas OPTIMIZE das tabelas InnoDB FULLTEXT ) que diminui o desempenho sob cargas pesadas de exclusão (sem reconstruir a tabela do zero).
Relacionado .
fonte
Os índices de texto completo no MySQL não foram projetados para suportar grandes quantidades de dados, portanto, a velocidade da pesquisa diminui rapidamente, à medida que seu conjunto de dados cresce. Uma das soluções é usar mecanismos externos de pesquisa de texto completo, como o Solr ou o Sphinx, que melhoraram a funcionalidade de pesquisa (ajuste de relevância e suporte à pesquisa de frases, facetas internas, trechos, etc.) sintaxe de consulta estendida e velocidade muito mais rápida em meados de conjuntos de dados grandes.
O Solr é baseado na plataforma Java, portanto, se você executar aplicativos baseados em Java, será uma escolha natural para você, o Sphinx será escrito em C ++ e atuará como um daemon da mesma maneira que o MySQL. Assim que você alimentar o mecanismo externo com os dados que deseja pesquisar, você também poderá mover algumas consultas para fora do MySQL. Não sei dizer qual mecanismo é melhor no seu caso, uso principalmente o Sphinx e aqui está um exemplo de uso: http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/
fonte