[英]How to do fulltext search in multiple columns in MySQL, quickly?
我知道这个问题已经被问过好几次了..但是,让我解释一下。
我有一个包含 450k 用户记录(id、名字、姓氏、地址、电话号码等)的表。 我想通过他们的名字和/或他们的姓氏搜索用户。
我使用了这些查询:
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 秒)。 这是我的问题。
为了解决这个问题,我尝试在 MATCH 和 AGAINST 两列上使用全文索引 'nom' 和 'prénom' :
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
最适合用于将完整单词分散在较长文本中的情况,这不是您的情况,因为您已将nom
和prénom
分开。
也许您不应该对这个模式中的任何内容使用MATCH
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.