【问题标题】:Increase speed of MySQL LIKE query?提高 MySQL LIKE 查询的速度?
【发布时间】:2012-03-31 19:27:57
【问题描述】:

对于具有自动完成功能的机场输入字段,目前有一个包含机场描述的表格,autocomplete_airport

lang | description (with INDEX)                           | ...
-----+----------------------------------------------------+----
pt   | New York - John F Kennedy (JFK), Estados Unidos    | ...
pt   | Nova Iorque - John F Kennedy (JFK), Estados Unidos | ...
...

自动完成功能适用于单个单词。因此,当用户输入“yor”时,会出现“new york”(如果在 LIMIT 中)。该查询目前的工作方式如下:

SELECT * FROM autocomplete_airport WHERE lang = "pt"
AND (description LIKE "%(yor)%"
     OR description LIKE "yor%"
     OR description LIKE "% yor%")
ORDER BY description
LIMIT 15

现在我想知道如何加快速度。一种想法是创建以下数据库结构,其中包含表autocomplete_airportautocomplete_airport_word

id   | lang | description (with INDEX)                           | ...
-----+------+----------------------------------------------------+----
123  | pt   | New York - John F Kennedy (JFK), Estados Unidos    | ...
124  | pt   | Nova Iorque - John F Kennedy (JFK), Estados Unidos | ...
...

word (with INDEX) | autocomplete_airport_id
------------------+------------------------
New               |                     123
York              |                     123
John              |                     123
F                 |                     123
Kennedy           |                     123
JFK               |                     123
...

那么 SELECT 只需要在字符串的开头进行搜索:

SELECT DISTINCT autocomplete_airport.*
FROM autocomplete_airport
INNER JOIN autocomplete_airport_word 
ON autocomplete_airport.id = autocomplete_airport_word.autocomplete_airport_id
WHERE lang = "pt"
AND word LIKE "yor%"
ORDER BY description
LIMIT 15

这种新结构值得麻烦吗?它真的会加快速度吗?有没有更简单的方法?

更新

刚刚注意到单词表有一个缺陷。结果:搜索“纽约”不会给出任何结果。什么应该起作用:

term (with INDEX)                               | autocomplete_airport_id
------------------------------------------------+------------------------
New York - John F Kennedy (JFK), Estados Unidos | 123
York - John F Kennedy (JFK), Estados Unidos     | 123
John F Kennedy (JFK), Estados Unidos            | 123
F Kennedy (JFK), Estados Unidos                 | 123
Kennedy (JFK), Estados Unidos                   | 123
(JFK), Estados Unidos                           | 123
Estados Unidos                                  | 123
Unidos                                          | 123
JFK                                             | 123

【问题讨论】:

    标签: mysql performance search


    【解决方案1】:

    您提出的方法可能会加快您的查询速度。 LIKE 查询的重要一点是通配符 % 不能位于模式的开头。

    LIKE '%foobar' 不能使用索引。 LIKE 'foobar%' 可以使用索引。

    但是,如果您只是有几百个机场要存储,我会三思而后行,如果全表扫描真的有那么大的伤害。

    使用EXPLAIN select {rest of query} 了解数据库如何以及是否正在使用。

    http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html (向下滚动到B-Tree Index Characteristics,这是默认的mysql索引类型)

    【讨论】:

    • 很高兴知道LIKE '%foobar' 不能使用索引。确实这就是EXPLAIN select {rest of query} 所显示的。现在我正在考虑是否使用全文搜索或我最初提出的单独的 word table。顺便说一句,每个lang 大约有 10,000 个条目。应该做一些分析......
    • 通过“只是”添加索引并稍微修改您的查询来解决它听起来非常诱人。我相信机场表中的数据是恒定的,因此 MyIsam 表在这里很好(您仍然可以不时执行“LOCK TABLE”:)。我会试一试。祝你好运
    【解决方案2】:

    正如 MartinK 所说,如果您的表只有几百行,即使没有优化,您的查询也应该很快 - 值得检查发生了什么。

    但是,搜索文本字段的最佳方法是使用全文索引 (http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html) - 这是专为你描述的情况。

    【讨论】:

    • 我不确定 mysql 全文索引功能。但是,“布尔全文搜索”(和 * 通配符)确实看起来对这个问题很有用。我有点担心“停用词”和“词干”(默认情况下未启用)会给用户带来一些意想不到的结果。 YMMV。无论如何,赞成:)
    • 看起来是最好的解决方案。不过,还没有申请,因为我首先需要得到客户的批准。在这种情况下添加索引并不容易,因为整个数据库都是 InnoDB(有充分的理由),并且系统中没有提供将单个表更改为 MyISAM 的功能。不过,我已经想到了解决这个问题的方法。
    • 如果我理解正确,FULLTEXT 不能使用通配符,所以对我来说没用
    • @MartinZvarík - 如果您定义了您的案例,这会有所帮助,但全文搜索实际上并没有“通配符”的概念 - 但它确实支持在中搜索 querystring目标列,无论该 querystring 的位置如何。有关示例,请参见 mysqltutorial.org/mysql-natural-language-search.aspx
    • @NevilleKuyt 我有像“SS2352”这样的随机字符,并且使用 FULLTEXT 作为 '*23*' 没有找到任何东西?‍♂️ ...所以我继续使用 LIKE
    猜你喜欢
    • 2016-04-27
    • 1970-01-01
    • 2019-10-09
    • 2021-11-17
    • 2021-12-24
    • 1970-01-01
    • 2023-04-01
    • 2018-05-17
    • 1970-01-01
    相关资源
    最近更新 更多