Koordinatlar tablosuna yardımcı alanlar eklerseniz, sorgunun yanıt süresini iyileştirebilirsiniz.
Bunun gibi:
CREATE TABLE `Coordinates` (
`id` INT(10) UNSIGNED NOT NULL COMMENT 'id for the object',
`type` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'type',
`sin_lat` FLOAT NOT NULL COMMENT 'sin(lat) in radians',
`cos_cos` FLOAT NOT NULL COMMENT 'cos(lat)*cos(lon) in radians',
`cos_sin` FLOAT NOT NULL COMMENT 'cos(lat)*sin(lon) in radians',
`lat` FLOAT NOT NULL COMMENT 'latitude in degrees',
`lon` FLOAT NOT NULL COMMENT 'longitude in degrees',
INDEX `lat_lon_idx` (`lat`, `lon`)
)
TokuDB kullanıyorsanız, tahminlerden herhangi birine kümeleme dizinleri eklerseniz daha da iyi performans elde edersiniz, örneğin, şöyle:
alter table Coordinates add clustering index c_lat(lat);
alter table Coordinates add clustering index c_lon(lon);
Temel lat ve lon dereceleri ve radyanlarda sin (lat), radyanlarda cos (lat) * cos (lon) ve her nokta için radyanlarda cos (lat) * sin (lon) gerekir. Sonra bir mysql işlevi, böyle smth oluşturun:
CREATE FUNCTION `geodistance`(`sin_lat1` FLOAT,
`cos_cos1` FLOAT, `cos_sin1` FLOAT,
`sin_lat2` FLOAT,
`cos_cos2` FLOAT, `cos_sin2` FLOAT)
RETURNS float
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY INVOKER
BEGIN
RETURN acos(sin_lat1*sin_lat2 + cos_cos1*cos_cos2 + cos_sin1*cos_sin2);
END
Bu size mesafeyi verir.
Sınırlayıcı boksun aramayı yavaşlatmak yerine aramaya yardımcı olabilmesi için lat / lon üzerine bir dizin eklemeyi unutmayın (dizin zaten CREATE TABLE sorgusuna eklenmiştir).
INDEX `lat_lon_idx` (`lat`, `lon`)
Yalnızca lat / lon koordinatlarına sahip eski bir tablo verildiğinde, bunu güncellemek için bir komut dosyası oluşturabilirsiniz: (php meekrodb kullanarak)
$users = DB::query('SELECT id,lat,lon FROM Old_Coordinates');
foreach ($users as $user)
{
$lat_rad = deg2rad($user['lat']);
$lon_rad = deg2rad($user['lon']);
DB::replace('Coordinates', array(
'object_id' => $user['id'],
'object_type' => 0,
'sin_lat' => sin($lat_rad),
'cos_cos' => cos($lat_rad)*cos($lon_rad),
'cos_sin' => cos($lat_rad)*sin($lon_rad),
'lat' => $user['lat'],
'lon' => $user['lon']
));
}
Daha sonra gerçek sorguyu yalnızca gerçekten gerekli olduğunda mesafe hesaplamasını yapmak için optimize edersiniz, örneğin daireyi (kuyu, oval) içten ve dıştan sınırlayarak. Bunun için, sorgunun kendisi için birkaç metriği önceden hesaplamanız gerekir:
// assuming the search center coordinates are $lat and $lon in degrees
// and radius in km is given in $distance
$lat_rad = deg2rad($lat);
$lon_rad = deg2rad($lon);
$R = 6371; // earth's radius, km
$distance_rad = $distance/$R;
$distance_rad_plus = $distance_rad * 1.06; // ovality error for outer bounding box
$dist_deg_lat = rad2deg($distance_rad_plus); //outer bounding box
$dist_deg_lon = rad2deg($distance_rad_plus/cos(deg2rad($lat)));
$dist_deg_lat_small = rad2deg($distance_rad/sqrt(2)); //inner bounding box
$dist_deg_lon_small = rad2deg($distance_rad/cos(deg2rad($lat))/sqrt(2));
Bu hazırlıklar göz önüne alındığında, sorgu şu şekilde gider (php):
$neighbors = DB::query("SELECT id, type, lat, lon,
geodistance(sin_lat,cos_cos,cos_sin,%d,%d,%d) as distance
FROM Coordinates WHERE
lat BETWEEN %d AND %d AND lon BETWEEN %d AND %d
HAVING (lat BETWEEN %d AND %d AND lon BETWEEN %d AND %d) OR distance <= %d",
// center radian values: sin_lat, cos_cos, cos_sin
sin($lat_rad),cos($lat_rad)*cos($lon_rad),cos($lat_rad)*sin($lon_rad),
// min_lat, max_lat, min_lon, max_lon for the outside box
$lat-$dist_deg_lat,$lat+$dist_deg_lat,
$lon-$dist_deg_lon,$lon+$dist_deg_lon,
// min_lat, max_lat, min_lon, max_lon for the inside box
$lat-$dist_deg_lat_small,$lat+$dist_deg_lat_small,
$lon-$dist_deg_lon_small,$lon+$dist_deg_lon_small,
// distance in radians
$distance_rad);
Yukarıdaki sorgudaki EXPLAIN, böyle bir tetikleme için yeterli sonuç olmadığı sürece dizin kullanmadığını söyleyebilir. Dizin, koordinatlar tablosunda yeterli veri olduğunda kullanılacaktır. FORCE INDEX (lat_lon_idx) öğesini SELECT öğesine tablo boyutuna bakmaksızın dizini kullanmasını sağlamak için ekleyebilirsiniz, böylece EXPLAIN ile doğru çalıştığını doğrulayabilirsiniz.
Yukarıdaki kod örnekleri ile, minimum hata ile mesafeye göre nesne arama çalışma ve ölçeklenebilir bir uygulama olması gerekir.