我正在使用此查询在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条记录
索引
无论出于何种原因,当我删除标记映射和标记时,搜索速度会大大加快。
您对如何加快此查询有任何提示吗?
提前致谢!
答案 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
,则此处不需要它。
如果我没有把一切都搞定,我道歉;转化比我预期的要多。