4

我正在使用此查询对 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 条记录

索引

  • 主要 BTREE - id
  • BTREE - 唯一代码
  • BTREE - 问题日期
  • BTREE - 用户标识
  • FULLTEXT - 问题文本
  • FULLTEXT - 唯一代码

答案- 3,635 条记录

索引

  • 初级 - BTREE - id
  • BTREE - 回答日期
  • BTREE - questionid
  • FULLTEXT - 答案文本

answer_mapping - 4,228 条记录

索引

  • 初级 - BTREE - id
  • BTREE - 回答ID
  • BTREE - questionid
  • BTREE - 用户标识

标签- 1,847 条记录

索引

  • 初级 - BTREE - id
  • BTREE - 标记
  • 全文 - 标记

标记映射- 3,389 条记录

索引

  • 初级 - BTREE - id
  • BTREE - 标记
  • BTREE - questionid

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

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

提前致谢!

4

3 回答 3

2

您也可以尝试运行 OPTIMIZE TABLE questions

它有助于加快我正在从事的项目中的类似查询。

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

于 2017-02-09T18:20:57.687 回答
1

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

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

您应该考虑使用dismax 请求处理程序使用 lucene/ solr 。它应该在大约 50 毫秒到 100 毫秒内为您提供良好的结果,并带有数十万个文档的索引。在某些时候,您可以对其进行分片,因此记录的数量实际上是无限的。加上你有更好的选择,可以取得更好的结果。例如进行模糊匹配或对较新的文档给予更多的权重或标签比标题更相关,进行查询后分析、分面等...

于 2010-10-03T01:21:24.317 回答
0

由于多种原因,您对查询的表述工作缓慢,但我不确定细节。请提供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,这里就不需要了。

如果我没有把所有事情都做对,我深表歉意;转变比我预期的要多。

于 2017-02-14T00:35:15.867 回答