MySql `MATCH AGAINST` 和 `LIKE` 组合搜索特殊字符

Posted

技术标签:

【中文标题】MySql `MATCH AGAINST` 和 `LIKE` 组合搜索特殊字符【英文标题】:MySql `MATCH AGAINST` and `LIKE` combination to search for special characters 【发布时间】:2021-12-20 11:58:30 【问题描述】:

例如,在数据库中,我有一个带有短语 DN-NP 的行。 在输入字段中,我输入 DN- 并希望找到该行。 这是示例http://sqlfiddle.com/#!9/f9235a/4 尝试使用FULLTEXT索引和MATCH AGAINST

SELECT `name` 
FROM `domains` 
WHERE MATCH (`name`) AGAINST ('DN*' IN BOOLEAN MODE);

没有结果。

这里https://dba.stackexchange.com/a/111895/55397 建议与LIKE 结合使用。目前的想法是在 php 中类似于

if( strlen($_POST['input_field_value']) <= 2 ) 
$sql = 'SELECT `name` 
FROM `domains` 
WHERE MATCH (`name`) AGAINST ('DN*' IN BOOLEAN MODE)
OR `name` LIKE "%DN%"'; 

但是 LIKE "% %" 太慢了?任何想法如何解决问题(查找包含特殊字符的短语)?

LOCATE(性能)呢?

SELECT name AS name7 
FROM domains 
WHERE LOCATE('DN',`name`)>0;

【问题讨论】:

【参考方案1】:

索引可以通过限制查看的行数来帮助提高速度。到目前为止显示的大多数代码都需要测试每一行。

FULLTEXT 非常擅长在其规则适用时查找行。由于字长和标点符号的存在,我怀疑+DN* 是否适用。 `LIKE "DN-NP%" 可以非常有效地使用索引。但这仅适用于列开头的字符串。 `LIKE "%DN-NP%" -- 前导通配符需要检查每一行。 LOCATE 和任何其他字符串运算符 -- 不可 sargable,因此需要查看每一行。 REGEXP "DN-NP" -- slower than LIKE. (There are other situations where REGEXPcan be faster and/orLIKE` 不适用。)

如果您将最小字长设置为 2,那么这个技巧可能是最有效的:

WHERE MATCH(col) AGAINST("+DN +NP" IN BOOLEAN MODE)
  AND col LIKE '%DN-NP%'

MATCH 将有效地减少行数; LIKE 将进一步减少数字或行数,但只查看MATCH 中的小数字。

警告:你需要匹配哪些不匹配?:

abc DN-NP def
abc DNs-NPed def   -- look likes "plural", etc which FULLTEXT matches
abc DN-NPQRS def   -- word boundary issue
abc ZYXDN-NP def

REGEXP 可以匹配“单词边界”; LIKE没有这样的。

请建立一个你想要匹配/不匹配的列表。我们可能会为您提供更好的答案。

【讨论】:

感谢您的建议。在输入字段中我输入DN 我想在mysql 中查找包含...的行实际上我想在任何位置找到包含DN 的所有行(所有四个示例)。如果在输入字段中输入DN-,我还想在任何位置找到包含DN- 的所有mysql 行。我的意思是,我想找到所有包含输入字符串(字符)的行 在sqlfiddle.com/#!9/28a3f3/9 中继续测试。似乎MATCH 的问题是,如果在输入字段中输入- 字符,那么IN BOOLEAN MODE 表示NOT。没有BOOLEAN MODE,什么都得不到。 LIKE%...% 正是我需要的。但据我所知,如果有很多行,速度太慢了。所以问题是如何减少LIKE 的行数。有趣的信息在这里***.com/a/41716705/2118559“我想评论一下,在我的案例中,创建索引还有助于加快类似 '%abc%' 的查询。” @Andris - SHOW VARIABLES LIKE 'innodb_ft_min_token_size'; 可能是 3,这意味着 DN 太短而无法编入索引。 是的,正确,最小值是 3。得到了[0] =&gt; Array ( [Variable_name] =&gt; innodb_ft_min_token_size [Value] =&gt; 3 ) @Andris - 如果将该设置更改为 2,则需要重新创建索引才能生效。【参考方案2】:

正则表达式怎么样?

选择名称作为名称6 来自域 WHERE name regexp ('DN');

【讨论】:

以上是关于MySql `MATCH AGAINST` 和 `LIKE` 组合搜索特殊字符的主要内容,如果未能解决你的问题,请参考以下文章

MySQL MATCH() AGAINST() 等效于 SQL Server

mysql 全文模糊搜索MATCH AGAINST方法

Mysql利用match...against进行全文检索

MySql `MATCH AGAINST` 和 `LIKE` 组合搜索特殊字符

mysql全文索引用于 MATCH() AGAINST 但不用于 =

MySQL ------ 全文本搜索( match和Against),以及查询扩展和 布尔方式(十七)