Optimization of MySQL search using "like" and wildcards

Jon*_*nas 15 mysql optimization wildcard

How can queries like

SELECT * FROM sometable WHERE somefield LIKE '%value%'
Run Code Online (Sandbox Code Playgroud)

be optimized?

The main issue here is the first wildcard which prevents DBMS from using index.

Edit: What is more, somefield value is solid string (not a piece of text) so fulltext search could not be performed.

Tim*_*imo 21

你的琴弦有多长?

如果它们相对较短(例如英文单词; avg_len = 5)并且您有备用数据库存储,请尝试以下方法:

  • 对于要存储在表中的每个单词,请改为使用该单词的每个可能后缀.换句话说,你继续剥离第一个字符,直到什么都没有留下.例如,这个词value给出:
    • value
    • alue
    • lue
    • ue
    • e
  • 将这些后缀中的每一个都存储在数据库中.
  • 您现在可以使用LIKE 'alu%'(将'alu'作为'value'的一部分)来搜索子字符串.

通过存储所有后缀,您无需使用前导通配符(允许使用索引进行快速查找),但需要以存储空间为代价.

存储成本

存储单词所需的字符数word_len*word_len / 2在每个单词的基础上变为字长的二次方.以下是各种单词大小的增加因素:

  • 3个字母的单词: (3*3/2) / 3 = 1.5
  • 5个字母的单词: (5*5/2) / 5 = 2.5
  • 7个字母的单词: (7*7/2) / 7 = 3.5
  • 12个字母的单词: (12*12/2) / 12 = 6

存储单词所需的行数从1增加到word_len.注意这个开销.应将其他列保持在最低限度,以避免存储大量冗余数据.例如,最初找到该单词的页码应该没问题(想想unsigned smallint),但是单词上的大量元数据应该基于每个单词而不是每个后缀存储在单独的表中.

注意事项

在我们分割"单词"(或片段)的地方存在权衡.作为一个现实世界的例子:我们用连字符做什么?我们将形容词存储five-letter为一个或两个单词吗?

权衡如下:

  • 任何被分解的东西都不能作为单个元素找到.如果我们存储fiveletter单独存储,搜索five-letterfiveletter将失败.
  • 任何分解的东西都会占用更多的存储空间.请记住,存储要求在字长中呈二次方增加.

为方便起见,您可能希望删除连字符和存储fiveletter.这个词现在可以通过搜索发现five,letterfiveletter.(如果您也从任何搜索查询中删除连字符,用户仍可以成功找到five-letter.)

最后,有一些存储后缀数组的方法不会产生太大的开销,但我还不确定它们是否可以很好地转换为数据库.

  • 这是一个非常好的答案,它是解决问题的唯一答案.(不可否认,它的限制是你的字符串必须足够短,以至于你不介意将行数乘以平均字符串长度,但这可能是不可避免的.) (4认同)

gbn*_*gbn 5

使用全文搜索。“初始想法”标题具有相同的示例,并导致可行的示例解决方案。

和 MySQL 文档

编辑:它不能在 SQL 本身中进行调整。使用 LOCATE 或 PATINEX 等函数也无济于事。


O. *_*nes 5

两种方式:

(1)使用内存中的表,它可以非常快速地运行。

(2)制定比更好的索引和搜索算法foo LIKE '%bar%'。如果不了解您的问题,就不可能对此提出任何建议。

正如您所指出的那样,%bar%模式可确保对每个查找进行表扫描,从而使数据库软件中任何可能的搜索独创性都无效。