【问题标题】:Improve performance on MySQL fulltext search query提高 MySQL 全文搜索查询的性能
【发布时间】:2015-07-02 10:38:26
【问题描述】:

我有以下 MySQL 查询:

SELECT p.*, MATCH (p.description) AGAINST ('random text that you can use in sample web pages or typography samples') AS score 
FROM posts p 
WHERE p.post_id <> 23 
AND MATCH (p.description) AGAINST ('random text that you can use in sample web pages or typography samples') > 0 
ORDER BY score DESC LIMIT 1

108,000 行,需要 ~200ms。有 265,000 行,需要 ~500ms

在性能测试中(~80 个并发用户)它显示 ~18sec 平均延迟。

有什么方法可以提高这个查询的性能吗?

解释输出:

更新

我们添加了一个带有post_iddescription 的新镜像 MyISAM 表,并通过触发器将其与posts 表同步。现在,在这个新的 MyISAM 表上进行全文搜索~400ms(与 InnoDB 显示的相同性能负载 ~18sec.. 这是一个巨大的性能提升)看起来 MyISAM 是MySQL 中的全文比 InnoDB 快得多。你能解释一下吗?

MySQL 分析器结果:

AWS RDS db.t2.small 实例上测试

原 InnoDB posts 表:

带有 post_id 的 MyISAM 镜像表,仅描述:

【问题讨论】:

  • 您使用的是哪个表引擎? MyISAM 还是 InnoDB?
  • 您了解为什么 InnoDB 查询需要 18 秒而分析信息加起来不到 0.5 秒吗?

标签: mysql sql full-text-search


【解决方案1】:

Here 是一些提示,以最大限度地提高 InnoDB 此类查询的速度:

  1. 避免冗余排序。由于 InnoDB 已经根据排名对结果进行了排序。 MySQL 查询处理层不需要 排序以获得最匹配的结果。

  2. 避免逐行提取以获取匹配计数。 InnoDB 提供所有匹配的记录。所有不在结果列表中的 都应该排名为0,不需要检索。和 InnoDB 手头有总匹配记录的计数。无需赘述。

  3. 覆盖索引扫描。 InnoDB 结果始终包含匹配记录的文档 ID 及其排名。因此,如果只有文档 ID 和 需要排名,不需要去用户表获取 记录自己。

  4. 尽早缩小搜索结果,减少用户表访问。如果用户想获取前 N 条匹配记录,我们不需要 fetch 用户表中的所有匹配记录。我们应该能够首先 选择TOP N个匹配的DOC ID,然后只取对应的 具有这些 Doc ID 的记录。

我认为仅查看查询本身并不能获得那么快的速度,也许可以尝试删除 ORDER BY 部分以避免不必要的排序。要深入研究这一点,可以使用MySQLs inbuild profiler 分析查询。

除此之外,您还可以查看 MySQL 服务器的配置。看看this chapter of the MySQL manual,它包含一些关于如何根据您的需要调整全文索引的好信息。

如果您已经最大限度地发挥 MySQL 服务器配置的功能,那么请考虑查看硬件本身 - 有时,即使是像将表移动到另一个更快的硬盘驱动器这样的成本损失解决方案也能产生奇迹。

【讨论】:

  • 这听起来很奇怪,但可能是完全不同的东西,比如查询缓存、错误的索引或其他东西。请尝试使用带有 InnoDB 和 MyISAM 的 MySQLs inbuild profiler 来分析查询以查找差异。
【解决方案2】:

这里的问题是WHERE p.post_id &lt;&gt; 23

以这样的方式设计您的系统,以便不需要将非索引列(如 post_id)添加到 WHERE 子句中。

基本上MySQL会搜索全文索引列,然后过滤post_id。因此,如果全文搜索返回的匹配项很多,则响应时间将不如预期。

【讨论】:

    【解决方案3】:

    我对性能影响的最佳猜测是查询返回的行数。要对此进行测试,只需删除 order by score 并查看这是否会提高性能。

    如果不是,那么问题是全文索引。如果是这样,那么问题是order by。如果是这样,问题就变得有点困难了。一些想法:

    • 确定硬件解决方案以加快排序(将中间文件保存在内存中)。
    • 修改查询使其返回更少的值。这可能涉及更改停用词列表、将查询更改为布尔模式或其他想法。
    • 寻找另一种预过滤结果的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-03
      • 2023-04-08
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多