2012-03-15 105 views
4

对于带有自动完成机场输入字段,目前有一个表,说明机场,autocomplete_airport提高MySQL LIKE查询的速度?

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

自动完成适用于单个单词。所以当用户输入“yor”时,“纽约”出现(如果在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 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 
+1

这样做! – fancyPants 2012-03-15 09:56:16

回答

5

由于MartinK说,如果你的表中有只有几百行,您的查询应该是相当快速即使没有优化 - 值得检查发生了什么。

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

+0

我不确定有关mysql全文索引功能。然而,'布尔全文搜索'(和*通配符)的确对这个问题看起来很有用。我有点害怕'停用词'和'阻塞'(默认情况下不启用)会给用户带来一些意想不到的结果。因人而异。无论如何,upvoted :) – MartinK 2012-03-15 10:46:35

+0

看起来像最好的解决方案。但是,还没有申请,因为我首先需要我的客户批准。在这种情况下添加索引并不容易,因为整个数据库都是InnoDB(出于很好的理由),并且系统中不提供将单个表更改为MyISAM的功能。尽管如此,我还是想过解决这个问题的一种方法。 – feklee 2012-03-19 16:31:42

4

您建议的方法可能会加快您的查询。 LIKE查询的重要之处在于通配符%不能位于模式的开头。

LIKE '%foobar'无法使用索引。 LIKE 'foobar%'可以使用索引。

但是,如果你只是有几百个机场来存储我会认为三次,如果一个全表扫描真的很伤害。

使用EXPLAIN select {rest of query}找出如何以及如果数据库正在使用。

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

+0

很高兴知道'LIKE'%foobar''不能使用索引。事实上,这就是'EXPLAIN select {rest of query}'节目。现在我正在考虑是否使用全文搜索或我最初提出的独立* word table *。顺便说一句,每个“lang”大约有10,000个条目。应该做一些分析... – feklee 2012-03-15 15:57:51

+0

解决它'只是'添加索引并修改您的查询有点听起来非常诱人。我相信机场表中的数据是不变的,所以MyIsam表格在这里很好(你可以不时地做'LOCK TABLE':)。我会给它一个镜头。祝你好运 – MartinK 2012-03-15 16:38:46