如何优化具有多个结果的 MySQL/MyISAM 全文搜索

Posted

技术标签:

【中文标题】如何优化具有多个结果的 MySQL/MyISAM 全文搜索【英文标题】:How to optimize a MySQL/MyISAM full text search with many results 【发布时间】:2019-09-28 22:53:15 【问题描述】:

我有一个 mysql MyISAM 表,其中包含关键字列和 2000 万行的全文索引。它在搜索稀有词时效果很好,例如:

SELECT count(*) FROM books WHERE MATCH(keywords) AGAINST ('+DUCK' IN BOOLEAN MODE)

(0.005 秒,2k 个结果)

但是当我搜索更常用的术语时,速度要慢得多:

SELECT count(*) FROM books WHERE MATCH(keywords) AGAINST ('+YES' IN BOOLEAN MODE)

(5 秒,200 万条结果)

这是有道理的,因为最后一个返回更多的行,但是我怎样才能在文本搜索之前预先过滤这些行呢?这不起作用:

SELECT count(*) FROM books WHERE date > "2019-09-23" AND MATCH(keywords) AGAINST ('+YES' IN BOOLEAN MODE)

(5s, 0 个结果)

【问题讨论】:

我建议放弃 MyISAM,因为 MySQL 开发人员正准备将 MyISAM 弃用和删除(可能很快),因为 InnoDB 的性能优于 MyiSAM(如果配置正确)数英里.. 为什么我认为 MySQL 开发人员是准备 MyISAM 被弃用?当 MySQL 需要使用基于(磁盘)的临时表处理查询时,MySQL 手册中有一个提示,您总是能够设置 internal_tmp_disk_storage_engine ... 但请注意 "在 MySQL 8.0.16 及更高版本中,磁盘内部临时表始终使用 InnoDB 存储引擎;从 MySQL 8.0.16 开始,此变量已被删除因此不再受支持。" 我切换到 MyISAM 是因为 InnoDB 的总体性能很糟糕。我使用 MySQL 5.7。例如,第一个查询可能需要 1 秒才能运行(使用 MyISAM 需要 0.005 秒) 顺便说一句,YES 是 MyISAM FTS 中的停用词。所以它永远不会被索引;搜索它也不会返回任何结果。所以基本上,没有搜索任何单词,这就是为什么它看起来像是发生了全表扫描。在此处查看停用词的完整列表:dev.mysql.com/doc/refman/8.0/en/… good catch @MadhurBhaiya 我没有注意到...无论如何我确定我知道你没有为 InnoDB 配置 MySQL 然后如果你声称/测试 MyISAM 比 InnoDB 更快。 .. 但是除了停用词之外,您还必须处理Minimum and Maximum Word Length settings,因为ft_min_word_len 设置默认为4,所以如果您从停用词列表中删除yes,它仍然没有被索引.. 【参考方案1】:

MyISAM 的(也许是 InnoDB 的)FULLTEXT 总是会先做 MATCH,然后是任何其他子句。因此,添加额外的过滤器对速度没有帮助。

这样想...构造一个 FT 索引来测试整个表的 MATCH 子句。它还没有准备好在它开始工作之前处理任何过滤。因此,您首先被 FT 卡住,然后以另一种方式过滤结果,但没有任何索引的好处。

【讨论】:

以上是关于如何优化具有多个结果的 MySQL/MyISAM 全文搜索的主要内容,如果未能解决你的问题,请参考以下文章

Django - 显示结果信息,同时使用具有多个外键关系的模型优化数据库查询

MYSQL MYISAM引擎与INNODB引引擎的区别

具有连接或多个结果集

如何使用具有多个 GROUP BY、子查询和 WHERE IN 在大表上的查询来优化查询?

网易笔试题——mysql整理

如何使用Pulp Gekko和Scipy软件包修复具有不同结果的代码以解决线性优化问题?