【问题标题】:MySQL FULLTEXT Search Across >1 TableMySQL FULLTEXT 搜索 >1 表
【发布时间】:2010-10-14 16:18:20
【问题描述】:

作为this question 的更一般情况,因为我认为更多人可能会对它感兴趣...在两个表上执行全文搜索的最佳方法是什么?假设有三张表,一张用于程序(带有submitter_id),一张用于标签和描述,带有object_id:外键引用程序中的记录。我们想要在标签或描述中包含特定文本的程序的 submitter_id。我们必须使用 MATCH AGAINST 原因我不会在这里讨论。不要纠结于这方面。

programs
  id
  submitter_id
tags_programs
  object_id
  text
descriptions_programs
  object_id
  text

以下工作并在 20 毫秒左右的时间内执行:

SELECT p.submitter_id
FROM programs p
WHERE p.id IN
    (SELECT t.object_id
    FROM titles_programs t
    WHERE MATCH (t.text) AGAINST ('china')
UNION ALL
    SELECT d.object_id
    FROM descriptions_programs d
    WHERE MATCH (d.text) AGAINST ('china'))

但我尝试将其重写为 JOIN,如下所示,它运行了很长时间。我必须在 60 秒后杀死它。

SELECT p.id 
FROM descriptions_programs d, tags_programs t, programs p
WHERE (d.object_id=p.id AND MATCH (d.text) AGAINST ('china'))
OR    (t.object_id=p.id AND MATCH (t.text) AGAINST ('china'))

出于好奇,我将 OR 替换为 AND。这也可以在几毫秒内运行,但这不是我需要的。上面的第二个查询有什么问题?我可以使用 UNION 和子选择,但我想了解。

【问题讨论】:

    标签: mysql full-text-search


    【解决方案1】:

    在过滤器之后加入(例如加入结果),不要尝试加入然后过滤。

    原因是您无法使用全文索引。

    对评论的澄清:我在这里一般使用 join 这个词,而不是 JOIN,而是作为合并或组合的同义词。

    我实质上是说您应该使用第一个(更快的)查询或类似的查询。它更快的原因是每个子查询都足够整洁,数据库可以使用该表的全文索引非常快速地进行选择。加入两个(可能要小得多)结果集(使用UNION)也很快。这意味着整个过程很快。

    慢速版本最终会遍历大量数据来测试它是否是您想要的,而不是快速筛选数据并仅搜索您可能真正需要的行。

    【讨论】:

    • 它的语法与第一个例子有什么不同吗?
    • 我不听,马库斯。 (a) 你会如何写“过滤后加入”?和 (b) '你失去了对全文索引的使用。???
    【解决方案2】:

    如果您同时加入这两个表,您最终需要检查大量记录。举个例子,如果两个表都有 100,000 条记录,则完全连接它们会得到 10,000,000,000 条记录(100 亿条!)。

    如果您通过 AND 更改 OR,那么您允许引擎从 table descriptions_programs 中过滤掉所有与 'china' 不匹配的记录,并且仅 然后 加入 title_programs。

    无论如何,这不是你需要的,所以我建议坚持使用 UNION 方式。

    【讨论】:

    • 这个数学正确吗?如果我有 100,000 个程序并且每个程序都有一个标题,为什么程序和标签的连接不会只产生 100,000 行?而且如果你还加入了 100,000 条描述,你不是仍然只有 100,000 行吗?
    • 如果你想匹配带有标题的节目,那么在join子句中匹配then。如果您只是在没有任何 ON 子句的情况下加入它们,则所有行都匹配。做类似 FROM descriptions_programs d JOIN tags_programs t ON d.object_id = t.objecT_id JOIN programs p ON t.object_id = p.id
    【解决方案3】:

    工会是正确的方法。连接将同时拉入两个全文索引,并且可以使实际执行的检查次数增加数倍。

    【讨论】:

      【解决方案4】:

      以防万一您不知道:MySQL 有一个名为EXPLAIN 的内置语句,可用于查看表面下发生的情况。有很多关于此的文章,所以我不会详细介绍,但对于每个表,它提供了它需要处理的行数的估计值。如果您查看第二个查询的 EXPLAIN 结果中的“rows”列,您可能会发现行数非常大,而且肯定比第一个查询大很多。

      网络上充斥着关于在 MySQL 中使用子查询的警告,但事实证明,很多时候开发人员比 MySQL 优化器更聪明。在许多情况下,在加入之前以某种方式过滤结果可以显着提升性能。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-06
        • 2013-06-04
        • 1970-01-01
        • 2019-02-07
        • 2014-08-29
        • 2010-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多