2012-12-22 39 views
2

我正在使用geonames.org的地理空间数据库。我目前在我的网站上有一个自动完成输入栏,它将搜索条件转发到数据库并返回适当的结果。重要的是,结果必须由国家订购。如何优化此MySQL查询的运行时间?

我从中选择约为900.000行大,并与创建表:

CREATE TABLE IF NOT EXISTS `geonames` (
`id` integer NOT NULL AUTO_INCREMENT PRIMARY KEY, 
`country_code` char(2) NOT NULL, 
`postal_code` varchar(20) NOT NULL, 
`place_name` varchar(180) NOT NULL, 
... 
FULLTEXT(country_code), 
FULLTEXT(postal_code), 
FULLTEXT(place_name) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; 

一个典型的说法是这样的:

SELECT postal_code, place_name FROM geonames WHERE LOWER(`place_name`) 
LIKE 'washin%' ORDER BY FIELD (country_code, 'JE', 'GB', 'FR', 'LI', 'CH', 
'DK', 'LU', 'BE', 'NL', ... many more countries in that list ...) DESC; 

我使用FULLTEXT超速指数在WHERE place_name LIKE 'washin%'部分。但是这个查询仍然有点慢。 SQL查询的任务是搜索表中与'washin%'匹配的每个place_name,然后根据指定的国家对结果进行排序。由于一次请求大量的数据,查询是否缓慢?如果是的话,我怎么能减少这个瓶颈的运行时间?

我不是任何方式的MySQL专家,所以我会很高兴,如果有人更有经验可以帮助我加快显示的SQL查询或至少指向我的方向去优化。

非常感谢!

回答

4

应避免LOWER在您的where子句,因为那时的指数不能被有效地使用:

SELECT postal_code, place_name FROM geonames 
WHERE `place_name` LIKE 'washin%' 
ORDER BY FIELD(country_code, 'JE', 'GB', ...) DESC; 

相反,你应该使用一个区分大小写的排序规则。以_ci结尾的排序规则不区分大小写。区分大小写的排序规则在_cs结束。

此外,您的全文索引将而不是帮助您使用LIKE查询。您应该在place_name上使用a B-TREE index

B树索引特征

A B树索引可以在使用表达式中使用列比较的=,>,> =,<,< =,或BETWEEN运算符。如果LIKE的参数是一个不以通配符开头的常量字符串,则该索引也可用于LIKE比较。

您也可以选择在索引中包含country_codepostal_code(但不作为第一列)。这会给你一个你的查询覆盖索引。

由于FIELD调用,ORDER BY也将无法有效地使用索引,但如果返回的结果数量相对较少,则不应成为问题。

+1

'MATCH(place_name)AGAINST('washin *'IN BOOLEAN MODE)'会使用全文索引吗? – Philipp

+0

@Philipp:是的,但它不等同于您的原始查询。 –

+0

因此,对于BTREE索引,我将删除所有'FULLTEXT'索引并执行'CREATE INDEX place_name_idx USING BTREE ON geonames(place_name);'? – Philipp

0

删除对LOWER函数的调用:在mysql中,LIKE忽略大小写,因此您不需要调用它。