慢MySQL全文搜索

时间:2010-10-03 00:02:25

标签: php mysql full-text-search full-text-indexing

我正在使用此查询在MySQL数据库上执行全文搜索:

SELECT DISTINCT 
questions.id, 
questions.uniquecode, 
questions.spam,
questions.questiondate,
questions.userid,
questions.description,
users.login AS username,
questions.questiontext,
questions.totalvotes,
MATCH(questions.questiontext, questions.uniquecode) 
AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) AS relevance 

FROM questions 

LEFT JOIN users ON questions.userid = users.id 
LEFT JOIN answer_mapping ON questions.id = answer_mapping.questionid 
LEFT JOIN answers ON answer_mapping.answerid = answers.id
LEFT JOIN tagmapping ON questions.id = tagmapping.questionid
LEFT JOIN tags ON tagmapping.tagid = tags.id 

WHERE questions.spam < 10 

AND 

(
  MATCH(questions.questiontext, questions.uniquecode) 
  AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) 

OR MATCH(answers.answertext) AGAINST ('rock guitarist chick*' IN BOOLEAN MODE) 

OR MATCH (tags.tag) AGAINST ('rock guitarist chick*' IN BOOLEAN MODE)

) GROUP BY questions.id ORDER BY relevance DESC

结果非常相关,但搜索速度非常慢,随着表格的增长而变得越来越慢。

表统计数据:

问题 - 400条记录

索引

  • PRIMARY BTREE - id
  • BTREE - uniquecode
  • BTREE - questiondate
  • BTREE - userid
  • FULLTEXT - 问题文字
  • FULLTEXT - uniquecode

答案 - 3,635条记录

索引

  • PRIMARY - BTREE - id
  • BTREE - 回答日期
  • BTREE - questionid
  • FULLTEXT - answertext

answer_mapping - 4,228条记录

索引

  • PRIMARY - BTREE - id
  • BTREE - answerid
  • BTREE - questionid
  • BTREE - userid

代码 - 1,847条记录

索引

  • PRIMARY - BTREE - id
  • BTREE - 标记
  • FULLTEXT - 标记

tagmapping - 3,389条记录

索引

  • PRIMARY - BTREE - id
  • BTREE - tagid
  • BTREE - questionid

无论出于何种原因,当我删除标记映射标记时,搜索速度会大大加快。

您对如何加快此查询有任何提示吗?

提前致谢!

3 个答案:

答案 0 :(得分:1)

您可以将您的联接组合到缓存视图或额外的表或其他内容中。让您的查询缓存处于活动状态,并将您的连接定义为选择,以便可以缓存它。确保足够的内存等,但这不应该成为瓶颈。很可能在你的情况下,因为...只有400条记录?没什么......而且已经慢了?因为其余的看起来不错。你在运行什么样的硬件/配置?

但是,我认为这是错误的做法。 mysql不是为此而设计的。实际上全文功能仅限于myisam。

你应该考虑使用dismax请求处理程序使用lucene / solr。 它应该在大约50ms-100ms给你很好的结果,索引一些hundret千文件。在某些时候你可以对它进行分片,因此记录的数量是非常无限的。 加上你有更好的选择,可以取得更好的结果。例如,做模糊匹配或给予较新文档更多权重或使标签与标题更相关,进行后查询分析,分面等...

答案 1 :(得分:0)

您也可以尝试运行 OPTIMIZE TABLE questions

它帮助加快了我正在进行的项目中的类似查询。

参见参考:https://dev.mysql.com/doc/refman/5.7/en/fulltext-fine-tuning.html

答案 2 :(得分:0)

由于多种原因,您对查询的表述工作缓慢,但我不确定细节。请提供EXPLAIN FORMAT=JSON SELECT ...进一步讨论。

同时,让我们以一种应该更快的方式重写查询。 (它可能会摆脱你尚未遇到的错误。)

首先,让我们构建一个调试。它在3个单独的查询中执行3 FT搜索,然后将UNION {/ 1}}组合在一起。

question_ids

注意每个子查询如何设计为启动,其中包含带有FT索引的表,最后得到 ( SELECT question_id, MATCH (... ) as relevance FROM questions WHERE MATCH (questiontext, ...) AGAINST ... ) UNION ALL ( SELECT am.question_id, MATCH (... ) as relevance FROM answers AS a JOIN answer_mapping AS am ON am.answerid = a.id WHERE MATCH (a.answertext) AGAINST ... ) UNION ALL ( SELECT tm.question_id, MATCH (... ) as relevance FROM tags AS t JOIN tagsmapping tm ON ... WHERE MATCH (t.tag) AGAINST ... )

现在,一个中间查询:

question_id

如果效果足够快,并提供“正确的”SELECT question_id, MAX(relevance) -- (this fixes the unseen bug) FROM ( that query ) AS q1 GROUP BY question_id ORDER BY relevance DESC -- optional; needed for `LIMIT` LIMIT 20 -- to limit the rows, do it at this stage ,那么我们就可以继续......

使用它作为子查询来获取其余数据:

question_ids

是的,这是SELECT .... -- the `questions` fields, using `q....`, ( SELECT login FROM users WHERE q.userid = id ) AS username FROM ( the intermediate query ) AS q2 JOIN questions AS q questions q.spam < 10 ORDER BY q2.relevance JOINing,但结果更快。

请注意,questions不在此处。并且,如果内部查询具有GROUP BY,则此处不需要它。

如果我没有把一切都搞定,我道歉;转化比我预期的要多。