如何在 MySQL 的多列中快速进行全文搜索?

How to do fulltext search in multiple columns in MySQL, quickly?

我知道这个问题已经被问过好几次了。但是,让我解释一下。

我有一个 table,其中包含 450k 条用户记录(ID、名字、姓氏、地址、phone 号码等)。 我想通过他们的名字 and/or 他们的姓氏来搜索用户。

我使用了这些查询:

SELECT * FROM correspondants WHERE nom LIKE 'Renault%' AND prénom LIKE 'r%';

SELECT * FROM correspondants WHERE CONCAT(nom, CHAR(32), prénom= LIKE 'Renault r%';

效果很好,但持续时间太长(1.5 秒)。这是我的问题。

为了修复它,我尝试在 'nom' 和 'prénom' 两个列上使用 MATCH 和 AGAINST 以及全文索引:

SELECT * FROM correspondants WHERE MATCH(nom, prénom) AGAINST('Renault r');

非常快(0,000 s ..)但是结果很糟糕,我没有得到我应该得到的。

例如,使用LIKE函数,结果为:

88623   RENAULT Rémy
91736   RENAULT Robin
202269  RENAULT Régine

(3 个结果)。

和 MATCH/AGAINST :

327380  RENAULT Luc
1559    RENAULT Marina
17280   RENAULT Anne
(...)
88623   RENAULT Rémy
91736   RENAULT Robin
202269  RENAULT Régine
(...)
436696  SEZNEC-RENAULT  Helene
(...)

(115 个结果!)

使用 "AND" 搜索对两列进行快速高效的文本搜索的最佳方法是什么? (以及索引呢)

全文搜索不像 LIKE 字符串比较那样进行模式匹配。全文搜索只搜索完整的单词,而不搜索像 r%.

这样的片段

还有一个字的最小大小,由 ft_min_word_len 配置变量控制。为避免使全文索引过大,它不会索引小于该变量的词。因此搜索时会忽略短词,因此 r 会被忽略。

在全文索引中也没有选择来搜索特定位置的单词,比如在字符串的开头。因此,您搜索 renault 可能会在字符串的中间找到。

要解决这些问题,您可以执行以下操作:

SELECT * FROM correspondants WHERE MATCH(nom, prénom) AGAINST('Renault')
  AND CONCAT(nom, CHAR(32), prénom) LIKE 'Renault r%';

这将使用全文索引来查找 450,000 行中字符串中某处包含单词 renault 的一小部分。然后搜索中的第二项将在没有索引帮助的情况下完成,但仅针对与第一项匹配的行子集。

该特定查询最好以这种方式完成:

INDEX(nom, prénom)

WHERE non = 'Relault' AND prénom LIKE 'R%'

我建议您添加该索引 将代码添加到您的应用程序中以不同的方式处理不同的请求。

不要在函数调用中隐藏索引列,如CONCAT(nom, ...),将无法使用索引;相反,它将检查每一行,对每一行执行 CONCAT,然后执行 LIKE。很慢。

除了首字母的情况(如上所述),您应该尽量避免使用非常短的名字。但是,这是另一种情况,您可以使用额外的代码使其工作:

WHERE nom = 'Lu'

(具有相同的索引)。请注意,使用任何风格的 MATCH 都可能效率低得多。

因此,如果您有完整的姓氏,请使用 WHERE nom =。如果给你一个前缀,那么使用 WHERE nom LIKE 'Prefix%'

可能会起作用

FULLTEXT 最适用于完整单词分散在较长文本中的情况,这不是您的情况,因为您将 nomprénom 分开了。

也许您不应该将 MATCH 用于此架构中的任何内容