[英]Slow MySQL full text search
我正在使用此查询在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条记录
索引
答案 - 3,635条记录
索引
answer_mapping - 4,228条记录
索引
标签 - 1,847条记录
索引
tagmapping - 3,389条记录
索引
无论出于何种原因,当我删除标记 映射和标记 JOINS时,搜索速度会大大提高。
您对如何加快查询速度有任何提示吗?
提前致谢!
好吧,你可以将你的连接组合成缓存视图或额外的表或其他东西。 让您的查询缓存处于活动状态,并将您的连接定义为选择,以便可以缓存它。 确保足够的内存等,但这不应该成为瓶颈。 很可能在你的情况下,因为...只有400条记录? 没什么......而且已经慢了? 因为其余的看起来不错。 你在运行什么样的硬件/配置?
但是,我认为这是错误的做法。 mysql不是为此而设计的。 实际上全文功能仅限于myisam。
你应该考虑使用dismax请求处理程序使用lucene / solr 。 它应该在大约50ms-100ms给你很好的结果,索引一些hundret千文件。 在某些时候你可以对它进行分片,因此记录的数量是非常无限的。 加上你有更好的选择,可以取得更好的结果。 例如,做模糊匹配或给予较新文档更多权重或使标签与标题更相关,进行后查询分析,分面等...
您也可以尝试运行OPTIMIZE TABLE questions
它帮助加快了我正在进行的项目中的类似查询。
参见参考: https : //dev.mysql.com/doc/refman/5.7/en/fulltext-fine-tuning.html
由于多种原因,您对查询的表述工作缓慢,但我不确定细节。 请提供EXPLAIN FORMAT=JSON SELECT ...
以供进一步讨论。
同时,让我们以一种应该更快的方式重写查询。 (它可能会摆脱你尚未遇到的错误。)
首先,让我们构建一个调试。 它在3个独立的查询中的3个FT搜索,然后组合( UNION
) 只是 question_ids
从每个。
( 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 ... )
注意每个子查询是如何设计为以带有FT索引的表开始 ,最后是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
不在此处。 并且,如果内部查询具有LIMIT
,则此处不需要它。
如果我没有把一切都搞定,我道歉; 有比我预期更多的转变。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.