2012-12-22 37 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忽略大小寫,因此您不需要調用它。