我正在使用geonames.org的地理空间数据库。我目前在我的网站上有一个自动完成输入字段,它将搜索字词转发到数据库并返回适当的结果。一个重要的是,结果必须按国家排序。
我选择的表大约有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查询的任务是搜索表中与place_name
匹配的每个'washin%'
,然后根据指定的国家/地区对结果进行排序。由于一次请求大量数据,查询是否会变慢?如果是,我怎么能减少这个瓶颈的运行时间呢?
我无论如何都不是MySQL的专家,所以如果有经验的人可以帮助我加快显示的SQL查询速度,或者至少指出我要进行优化的方向,我会很高兴。
非常感谢!
答案 0 :(得分:4)
你应该避免在where子句中使用LOWER
,因为这样就无法有效地使用索引:
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树索引特征
B树索引可用于使用=,>,> =,<,< =或BETWEEN运算符的表达式中的列比较。如果LIKE的参数是一个不以通配符开头的常量字符串,则该索引也可用于LIKE比较。
您还可以选择在索引中包含country_code
和postal_code
(但不包括第一列)。然后,这将为您的查询提供覆盖索引。
由于ORDER BY
调用,FIELD
也无法有效使用索引,但如果返回的结果数量相对较小,那么这应该不是问题。
答案 1 :(得分:0)
删除对LOWER
函数的调用:在mysql中,LIKE
忽略大小写,因此您无需调用它。