使用 fts + 复合索引优化查询
Posted
技术标签:
【中文标题】使用 fts + 复合索引优化查询【英文标题】:Optinimizing query with fts + composite index 【发布时间】:2020-01-17 23:24:14 【问题描述】:我有以下疑问:
SELECT *
FROM table
WHERE
structural_type=1
AND parent_id='167F2-F'
AND points_to_id=''
# AND match(search) against ('donotmatch124213123123')
搜索运行大约需要 10 毫秒,在复合索引(structural_type、parent_id、points_to_id)上运行。但是,当我添加 fts 索引时,无论匹配条件中包含什么,查询都会膨胀到大约 1 秒。基本上,每当我应用 fts 搜索时,它似乎都会“跳过索引”。
优化此查询的最佳方法是什么?
更新:一些解释:
EXPLAIN SELECT... # without fts
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table NULL ref structural_type structural_type 209 const,const,const 2 100.00 NULL
使用 fts(同时添加“强制索引”):
explain SELECT ... force INDEX (structural_type) AND match...
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table NULL fulltext structural_type,search search 0 const 1 5.00 Using where; Ft_hints: sorted
我能想到的唯一一件令人难以置信的骇人听闻的事情就是在 fts 中添加一个附加术语,以便它在“内部”执行过滤器。例如:
fts_term = fts_term += " StructuralType1ParentID167F2FPointsToID"
【问题讨论】:
查询的注释版本返回多少个结果? @BenoitEsnard 2 个结果。桌子大小为 2.4m。 @David542:你在桌子上运行OPTIMIZE TABLE
查询了吗?
不同模式对搜索表达式使用不同的语法,表达式的结果返回不同的值。我宁愿参考文档而不是全部输入:dev.mysql.com/doc/refman/8.0/en/fulltext-search.html
我来自 PostgreSQL 背景,所以我不确定 MySQL 内部是如何在这里真正工作的。在 PostgreSQL 中,您需要对表进行一些维护(数据统计,在您的情况下),所以我想这里是一样的。
【参考方案1】:
MySQL 优化器只能为您的 WHERE 子句使用一个索引,因此它必须在复合索引和 FULLTEXT 索引之间进行选择。
由于它不能同时运行两个查询来确定哪个更快,它会估计不同执行计划的速度。
为此,MySQL 使用它保存的有关每个表的一些内部统计信息。但是,如果这些统计数据没有更新并且表格中的数据发生变化,这些统计数据可能与实际情况大不相同。
运行OPTIMIZE TABLE table
查询允许 MySQL 刷新其表统计信息,因此它将能够执行更好的估计并选择更好的索引。
【讨论】:
【参考方案2】:尝试在没有全文逻辑的情况下表达这一点,使用like
:
SELECT *
FROM table
WHERE structural_type = 1 AND
parent_id ='167F2-F' AND
points_to_id = '' AND
search not like '%donotmatch124213123123%';
索引仍应用于前三列。 LIKE
可能会很慢,但如果没有多少行与前三个匹配,这可能不如使用全文索引那么糟糕。
【讨论】:
这是一个可能的解决方案,尽管在我的问题中我没有包含多个术语,而在其他查询中我可能需要在 fts 索引中使用多个术语。 @David542 。 . .如果这有更好的性能,您可以尝试使用正则表达式。以上是关于使用 fts + 复合索引优化查询的主要内容,如果未能解决你的问题,请参考以下文章
注意使用 BTREE 复合索引各字段的 ASC/DESC 以优化 order by 查询效率