約300kのレコードを含むmysql(5.0.22)myisamテーブルがあり、半径5マイル以内で緯度/経度の距離検索を実行したいと考えています。
lat / lonフィールドをカバーするインデックスがあり、lat / lonを選択するだけで高速(ミリ秒応答)になります。しかし、テーブルで追加のフィールドを選択すると、5〜8秒にひどく遅くなります。
全文検索を利用するためにmyisamを使用しています。他のインデックスはうまく機能します(たとえば、slug ='xxxxx'のリストから*を選択します)。
クエリ、テーブル、またはインデックスを最適化して処理を高速化するにはどうすればよいですか?
私のスキーマは次のとおりです。
CREATE TABLE `Listing` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(125) collate utf8_unicode_ci default NULL,
`phone` varchar(18) collate utf8_unicode_ci default NULL,
`fax` varchar(18) collate utf8_unicode_ci default NULL,
`email` varchar(55) collate utf8_unicode_ci default NULL,
`photourl` varchar(55) collate utf8_unicode_ci default NULL,
`thumburl` varchar(5) collate utf8_unicode_ci default NULL,
`website` varchar(85) collate utf8_unicode_ci default NULL,
`categoryid` int(10) unsigned default NULL,
`addressid` int(10) unsigned default NULL,
`deleted` tinyint(1) default NULL,
`status` int(10) unsigned default '2',
`parentid` int(10) unsigned default NULL,
`organizationid` int(10) unsigned default NULL,
`listinginfoid` int(10) unsigned default NULL,
`createuserid` int(10) unsigned default NULL,
`createdate` datetime default NULL,
`lasteditdate` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`lastedituserid` int(10) unsigned default NULL,
`slug` varchar(155) collate utf8_unicode_ci default NULL,
`aclid` int(10) unsigned default NULL,
`alt_address` varchar(80) collate utf8_unicode_ci default NULL,
`alt_website` varchar(80) collate utf8_unicode_ci default NULL,
`lat` decimal(10,7) default NULL,
`lon` decimal(10,7) default NULL,
`city` varchar(80) collate utf8_unicode_ci default NULL,
`state` varchar(10) collate utf8_unicode_ci default NULL,
PRIMARY KEY (`id`),
KEY `idx_fetch` USING BTREE (`slug`,`deleted`),
KEY `idx_loc` (`state`,`city`),
KEY `idx_org` (`organizationid`,`status`,`deleted`),
KEY `idx_geo_latlon` USING BTREE (`status`,`lat`,`lon`),
FULLTEXT KEY `idx_name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC;
私の質問は:
SELECT Listing.name, Listing.categoryid, Listing.lat, Listing.lon
, 3956 * 2 * ASIN(SQRT( POWER(SIN((Listing.lat - 37.369195) * pi()/180 / 2), 2) + COS(Listing.lat * pi()/180) * COS(37.369195 * pi()/180) * POWER(SIN((Listing.lon --122.036849) * pi()/180 / 2), 2) )) rawgeosearchdistance
FROM Listing
WHERE
Listing.status = '2'
AND ( Listing.lon between -122.10913433498 and -121.96456366502 )
AND ( Listing.lat between 37.296909665016 and 37.441480334984)
HAVING rawgeosearchdistance < 5
ORDER BY rawgeosearchdistance ASC;
ジオサーチなしで計画を説明する:
+ ---- + ------------- + ------------ + ------- + --------- -------- + ----------------- + --------- + ------ + ------ + ------------- + | id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ| + ---- + ------------- + ------------ + ------- + --------- -------- + ----------------- + --------- + ------ + ------ + ------------- + | 1 | シンプル| リスト| 範囲| idx_geo_latlon | idx_geo_latlon | 19 | NULL | 453 | whereを使用する| + ---- + ------------- + ------------ + ------- + --------- -------- + ----------------- + --------- + ------ + ------ + ------------- +
ジオサーチで計画を説明する:
+ ---- + ------------- + ------------ + ------- + --------- -------- + ----------------- + --------- + ------ + ------ + ----------------------------- + | id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ| + ---- + ------------- + ------------ + ------- + --------- -------- + ----------------- + --------- + ------ + ------ + ----------------------------- + | 1 | シンプル| リスト| 範囲| idx_geo_latlon | idx_geo_latlon | 19 | NULL | 453 | whereを使用する; filesortの使用| + ---- + ------------- + ------------ + ------- + --------- -------- + ----------------- + --------- + ------ + ------ + ----------------------------- +
これがカバーリングインデックス付きの説明プランです。列を正しい順序にすることで、大きな違いが生まれました。
+ ---- + ------------- + -------- + ------- + ------------- -+ --------------- + --------- + ------ + -------- + ----- ------------------------------------- + | id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ| + ---- + ------------- + -------- + ------- + ------------- -+ --------------- + --------- + ------ + -------- + ----- ------------------------------------- + | 1 | シンプル| リスト| 範囲| idx_geo_cover | idx_geo_cover | 12 | NULL | 453 | whereを使用する; インデックスを使用します。filesortの使用| + ---- + ------------- + -------- + ------- + ------------- -+ --------------- + --------- + ------ + -------- + ----- ------------------------------------- +
ありがとうございました!