提高 MySQL 全文搜索查询的性能

Improve performance on MySQL fulltext search query

我有以下 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 行,需要 ~200 毫秒。 265,000 行,需要 ~500ms.

根据性能测试(~80 个并发用户),它显示 ~18 秒 平均延迟。

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

解释输出:

已更新

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

MySQL 分析器结果:

AWS RDS 数据库上测试。t2.small 实例

原始InnoDB posts table:

MyISAM 镜像 table 与 post_id,仅描述:

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

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

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

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

  1. Avoid redundant sorting. Since InnoDB already sorted the result according to ranking. MySQL Query Processing layer does not need to sort to get top matching results.

  2. Avoid row by row fetching to get the matching count. InnoDB provides all the matching records. All those not in the result list should all have ranking of 0, and no need to be retrieved. And InnoDB has a count of total matching records on hand. No need to recount.

  3. Covered index scan. InnoDB results always contains the matching records' Document ID and their ranking. So if only the Document ID and ranking is needed, there is no need to go to user table to fetch the record itself.

  4. Narrow the search result early, reduce the user table access. If the user wants to get top N matching records, we do not need to fetch all matching records from user table. We should be able to first select TOP N matching DOC IDs, and then only fetch corresponding records with these Doc IDs.

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

分析查询

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

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

这里的问题是WHERE p.post_id <> 23

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

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