【发布时间】:2011-08-19 13:08:39
【问题描述】:
我的桌子目前是这样的:
CREATE TABLE IF NOT EXISTS `x_geodata` (
`post_id` int(11) NOT NULL,
`post_type` varchar(20) NOT NULL,
`lat` float(10,6) NOT NULL,
`lng` float(10,6) NOT NULL,
PRIMARY KEY (`post_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
我如何正确有效地索引这个表?
在这张表上运行的唯一查询如下:
if(!empty($_SESSION['s_property_radius'])) {$dist = $_SESSION['s_property_radius'];}else{$dist = 50;}
$orig_lat = $_SESSION['s_property_address_lat'];
$orig_lon = $_SESSION['s_property_address_lng'];
$lon1 = $orig_lon - $dist / abs( cos( deg2rad( $orig_lat ) ) * 69 );
$lon2 = $orig_lon + $dist / abs( cos( deg2rad( $orig_lat ) ) * 69 );
$lat1 = $orig_lat - ( $dist / 69 );
$lat2 = $orig_lat + ( $dist / 69 );
$sql = "
SELECT `t`.`post_id`, 3956 * 2 * ASIN( SQRT( POWER( SIN( ( ".$orig_lat." - `t`.`lat` ) * pi() / 180 / 2), 2 ) + COS( ".$orig_lat." * pi() / 180) * COS( `t`.`lat` * pi() / 180 ) * POWER( SIN( ( ".$orig_lon." - `t`.`lng` ) * pi() / 180 / 2 ), 2 ) ) ) AS `distance` FROM (
SELECT `post_id`, `lat`, `lng` FROM `x_geodata` WHERE `post_type` = 'some post type' AND `lng` BETWEEN '".$lon1."' AND '".$lon2."' AND `lat` BETWEEN '".$lat1."' AND '".$lat2."'
) AS `t` HAVING `distance` <= ".$dist."
";
查询检查以确保我们正在查看正确的帖子类型,然后对 lat 和 lng 进行方形半径检查。然后将返回的结果通过圆形半径检查。
我正在寻找的是更新 CREATE TABLE SQL 或 UPDATE TABLE SQL 以正确获取此 INDEXED。
非常感谢任何帮助。
编辑: 根据 arnep 答案对我的查询进行了解释,我得到了这个:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3
2 DERIVED zch_geodatastore range post_type post_type 70 NULL 3 Using where
虽然不知道是什么意思...
【问题讨论】:
-
您的
EXPLAIN有两部分:一是外部选择,二是内部选择。内部选择通过使用您的WHERE子句按预期使用您的新索引,它返回 3 行。外部选择使用这个没有任何索引的“派生”表......但不要担心:因为它正在为每一行计算一些东西,所以不需要索引。有关内部选择的更多信息,您可以在其上执行另一个EXPLAIN。顺便说一句:你的CREATE TABLE使用lon,你的SELECT使用lng...令人困惑。而且您的内部选择不会返回lat和lng...缺少某些东西? -
我已经更新了我的代码。表应该是 lng 而不是 lon。我已将
lat和lng添加到内部查询中。不知道我发布此代码时是如何错过它们的。
标签: mysql geolocation latitude-longitude