यदि आप निर्देशांक तालिका में सहायक क्षेत्र जोड़ते हैं, तो आप क्वेरी की प्रतिक्रिया समय में सुधार कर सकते हैं।
ऐशे ही:
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 का उपयोग कर रहे हैं, तो आप और भी बेहतर प्रदर्शन प्राप्त करेंगे यदि आप किसी भी विधेय पर क्लस्टरिंग इंडेक्स जोड़ते हैं, उदाहरण के लिए, इस तरह:
alter table Coordinates add clustering index c_lat(lat);
alter table Coordinates add clustering index c_lon(lon);
आपको मूल अक्षांश और डिग्री के साथ-साथ रेडियन में पाप (lat), रेडियन में cos (lat) * cos (lon) और प्रत्येक बिंदु के लिए radians में cos (lat) * sin (lon) की आवश्यकता होगी। फिर आप एक mysql फ़ंक्शन बनाएं, इस तरह से smth करें:
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
इससे आपको दूरी मिलती है।
Lat / lon पर एक इंडेक्स जोड़ना न भूलें, ताकि बाउंडिंग बॉक्सिंग इसे धीमा करने के बजाय खोज में मदद कर सके (इंडेक्स पहले से क्रिएट टेबल क्वेरी में ऊपर जोड़ा गया है)।
INDEX `lat_lon_idx` (`lat`, `lon`)
केवल लेट / लोन निर्देशांक वाली एक पुरानी तालिका को देखते हुए, आप इसे इस तरह से अपडेट करने के लिए एक स्क्रिप्ट सेट कर सकते हैं: (meprodb का उपयोग करके php)
$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']
));
}
फिर आप वास्तविक क्वेरी का अनुकूलन केवल उस दूरी की गणना के लिए करते हैं जब वास्तव में जरूरत होती है, उदाहरण के लिए सर्कल (अच्छी तरह से, अंडाकार) को अंदर और बाहर से बांधकर। उसके लिए, आपको स्वयं क्वेरी के लिए कई मीट्रिक तैयार करने होंगे:
// 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));
उन तैयारियों को देखते हुए, क्वेरी कुछ इस तरह से होती है (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);
उपर्युक्त प्रश्न पर यह कह सकते हैं कि जब तक कि इस तरह के ट्रिगर करने के लिए पर्याप्त परिणाम न हों, यह सूचकांक का उपयोग नहीं कर रहा है। निर्देशांक तालिका में पर्याप्त डेटा होने पर सूचकांक का उपयोग किया जाएगा। आप तालिका के आकार के संबंध में सूचकांक का उपयोग करने के लिए चयन करने के लिए FORCE INDEX (lat_lon_idx) को जोड़ सकते हैं, ताकि आप EXPLAIN से सत्यापित कर सकें कि यह सही ढंग से काम कर रहा है।
उपरोक्त कोड नमूनों के साथ आपके पास न्यूनतम त्रुटि के साथ दूरी द्वारा ऑब्जेक्ट खोज का एक कार्यशील और मापनीय कार्यान्वयन होना चाहिए।