使用“like”和通配符优化MySQL搜索

时间:2010-01-17 18:01:00

标签: mysql optimization wildcard

如何查询

SELECT * FROM sometable WHERE somefield LIKE '%value%'

优化?

这里的主要问题是第一个阻止DBMS使用索引的通配符。

编辑:更重要的是,某些字段值是实心字符串(不是一段文字),因此无法进行全文搜索。

4 个答案:

答案 0 :(得分:21)

你的琴弦有多长时间?

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

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

通过存储所有后缀,您已经删除了对前导通配符的需求(允许使用索引进行快速查找),但代价是存储空间。

存储费用

在每个单词的基础上,存储单词所需的字符数变为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),但是单词上的大量元数据应该基于每个单词存储在单独的表中,而不是每个后缀。

<强>考虑

在我们拆分的地方进行权衡取舍&#39; (或片段)。作为一个现实世界的例子:我们用连字符做什么?我们将形容词five-letter存储为一个或两个词吗?

权衡如下:

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

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

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

答案 1 :(得分:4)

使用Full Text Search。 “初步想法”标题具有相同的示例,并导致工作示例解决方案。

And the MySQL docs

编辑:无法在SQL本身进行调整。使用LOCATE或PATINEX等功能也无济于事。

答案 2 :(得分:4)

考虑到你的问题是通配符,它​​不会产生很大的不同,但是不使用“SELECT *”会提高查询性能。如果你实际上并没有使用你得到的所有字段,那就是胜利,“SELECT *”会导致两个查询被触发,一个用于查找表的字段,然后查询添加了字段名称的查询。

答案 3 :(得分:4)

两种方式:

(1)使用内存表,因此速度非常快。

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

正如您所指出的,%bar%模式保证了每次查找的表扫描,这使数据库软件中任何可能的搜索独创性无效。