【问题标题】:MySQL FULLTEXT Search Running Extremely SlowlyMySQL FULLTEXT 搜索运行非常缓慢
【发布时间】:2023-03-03 04:55:22
【问题描述】:

处理少于​​ 50 行的小型数据集,下面的查询绝对可以正常工作。当扩展它并在大约 5000 行的数据集上运行相同的查询时,这个查询大约需要 3-6 秒才能运行,这在实时环境中太慢了。

可以做些什么来提高这个查询的性能?

SELECT table1.ID, table1.CompanyName, 
(SELECT CompanyIDBeingFollowed FROM table2 WHERE PersonID = ? ) 
FROM table1 
JOIN table3 ON table1.ID = table3.ID  
WHERE table1.Status = 'Live'  AND  ( MATCH(table3.Content) AGAINST( '+search +term' IN BOOLEAN MODE ) )  
GROUP BY table1.CompanyID 
LIMIT 10;

本质上,上面的查询是在一个大数据集中搜索,使用 MySQL FullText 对结果进行排名,以便返回最相关的结果,即 MySQL FullText 分数最高的结果。然后根据匹配的内容从另外两个表中获取一些信息,用于在页面上为用户填充有用的内容。

想法?

我意识到当前大约 5000 行的数据集将在短时间内增长到数十万行,因此我宁愿现在而不是以后研究如何最好地优化此查询。

在开发环境中,查询会立即运行,因为这是在大约 50 行的数据集上运行的。

更新

我刚刚更新了上面的 SQL,使其更易于阅读和理解。下表汇总供参考。

Table 1 - Companies
 - ID
 - CompanyName

Table 2 - People Following Companies
 - CompanyIDBeingFollowed
 - PersonID

Table 3 - Pages On Company Website
 - ID (Unique)
 - CompanyID (Non-Unique)
 - Content

【问题讨论】:

  • 能否请您发布一个实际查询的实例,其中不包含所有这些引号和 + 参数已被限制的符号
  • 并发布 table1 和 table2 的结构。添加解释。
  • @e4c5 更新问题
  • "您能否发布一个实际查询的实例,没有所有这些引号和 + 符号,其中参数已被限制"并且show create table 的结果对我们来说会更有用,并且为您减少打字次数
  • 整个表格中有很多与这个问题无关的无用信息,因此我没有包括在内以使事情更容易理解(希望是这样的)无论如何:-))

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


【解决方案1】:

很难回答您的问题,但是如果我在您的位置上,我会尝试这样做:

  1. 使用 explain 来检查那里发生了什么
  2. 确保我真的需要group by
  3. 确保我确实需要 `(SELECT ID FROM table2 WHERE ID = ?) 作为子查询
  4. 确保我真的需要order by

而且,当用户按一个词过滤数据时,使用“like”搜索而不是全文搜索是可以接受的。

【讨论】:

  • 1) Explain 并没有真正给我任何有用的信息。它只显示查询以及它是如何分解的,而不是为什么它需要一段时间才能运行。 2)我目前需要GROUP BY的原因是由于Table1和Table 3之间的JOIN,表1包含一个唯一的标识符ID,而Table3包含对此的多个引用,ID形式为CompanyID,用于多个行,每一行代表公司网站上的一个页面。我在这里大声思考,如果我将表 3 中的 CompanyID 设为表 1 的 ID 的外键,我能摆脱 GROUP BY 吗?
  • 3) 是的,很遗憾。 4)不,我实际上不需要,因为 MySQL FULLTEXT 搜索会自动返回一个优先列表,所以我已经删除了它。有趣的是,FULLTEXT 搜索中的单个词查询比多个词查询运行得慢,所以使用 LIKE 肯定会加快速度,好主意。 @degr
  • (SELECT CompanyIDBeingFollowed FROM table2 WHERE PersonID = ? ) 看起来它应该为所有行返回相同的结果,所以我认为你可以在不同的查询中做到这一点
【解决方案2】:

运行大约需要 3-6 秒(原始问题中的代码);

SELECT table1.ID, table1.CompanyName, 
(SELECT CompanyIDBeingFollowed FROM table2 WHERE PersonID = ? ) 
FROM table1 
JOIN table3 ON table1.ID = table3.ID  
WHERE table1.Status = 'Live'  AND  ( MATCH(table3.Content) AGAINST( '+search +term' IN BOOLEAN MODE ) )  
GROUP BY table1.CompanyID 
LIMIT 10;

鉴于此代码运行时间不到 1 秒(正如预期的那样) - 删除了 GROUP BY 并改用了 DISTINCT;

SELECT DISTINCT(table1.ID), table1.CompanyName, 
(SELECT CompanyIDBeingFollowed FROM table2 WHERE PersonID = ? ) 
FROM table1 
JOIN table3 ON table1.ID = table3.ID  
WHERE table1.Status = 'Live'  AND  ( MATCH(table3.Content) AGAINST( '+search +term' IN BOOLEAN MODE ) )  
LIMIT 10;

我不知道为什么在这种情况下会出现这种情况,但它确实有效。如果有人知道为什么会出现这种情况的更多技术方面,那就太好了,我会更新答案。

感谢大家的指点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多