अपनी SQL क्वेरी के WHERE क्लॉज में पंक्तियों के एक सबसेट का चयन करने के लिए एक बाउंडिंग बॉक्स की गणना करें, ताकि आप केवल अपनी तालिका में संपूर्ण 200k रिकॉर्ड के बजाय पंक्तियों के उस सबसेट पर महंगी दूरी की गणना निष्पादित कर रहे हों। इस विधि का वर्णन इस चल प्रकार पर लेख में किया गया है। (PHP कोड उदाहरणों के साथ)। फिर आप वास्तविक दूरी की गणना करने के लिए उस सबसेट के विरुद्ध अपनी क्वेरी में Haversine गणना शामिल कर सकते हैं, और उस बिंदु पर HAVING क्लॉज में कारक शामिल कर सकते हैं।
यह बाउंडिंग बॉक्स है जो आपके प्रदर्शन में मदद करता है, क्योंकि इसका मतलब है कि आप केवल अपने डेटा के एक छोटे से सबसेट पर महंगी दूरी की गणना कर रहे हैं। यह प्रभावी रूप से वही तरीका है जो पैट्रिक ने सुझाया है, लेकिन मूवेबल टाइप लिंक में विधि की व्यापक व्याख्या है, साथ ही PHP कोड भी है जिसका उपयोग आप बाउंडिंग बॉक्स और अपनी SQL क्वेरी बनाने के लिए कर सकते हैं।
संपादित करें
अगर आपको नहीं लगता कि हैवरसाइन काफी सटीक है, तो विंसेंटी फॉर्मूला भी है।
// Vincenty formula to calculate great circle distance between 2 locations expressed as Lat/Long in KM
function VincentyDistance($lat1,$lat2,$lon1,$lon2){
$a = 6378137 - 21 * sin($lat1);
$b = 6356752.3142;
$f = 1/298.257223563;
$p1_lat = $lat1/57.29577951;
$p2_lat = $lat2/57.29577951;
$p1_lon = $lon1/57.29577951;
$p2_lon = $lon2/57.29577951;
$L = $p2_lon - $p1_lon;
$U1 = atan((1-$f) * tan($p1_lat));
$U2 = atan((1-$f) * tan($p2_lat));
$sinU1 = sin($U1);
$cosU1 = cos($U1);
$sinU2 = sin($U2);
$cosU2 = cos($U2);
$lambda = $L;
$lambdaP = 2*M_PI;
$iterLimit = 20;
while(abs($lambda-$lambdaP) > 1e-12 && $iterLimit>0) {
$sinLambda = sin($lambda);
$cosLambda = cos($lambda);
$sinSigma = sqrt(($cosU2*$sinLambda) * ($cosU2*$sinLambda) + ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda) * ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda));
//if ($sinSigma==0){return 0;} // co-incident points
$cosSigma = $sinU1*$sinU2 + $cosU1*$cosU2*$cosLambda;
$sigma = atan2($sinSigma, $cosSigma);
$alpha = asin($cosU1 * $cosU2 * $sinLambda / $sinSigma);
$cosSqAlpha = cos($alpha) * cos($alpha);
$cos2SigmaM = $cosSigma - 2*$sinU1*$sinU2/$cosSqAlpha;
$C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha));
$lambdaP = $lambda;
$lambda = $L + (1-$C) * $f * sin($alpha) * ($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)));
}
$uSq = $cosSqAlpha*($a*$a-$b*$b)/($b*$b);
$A = 1 + $uSq/16384*(4096+$uSq*(-768+$uSq*(320-175*$uSq)));
$B = $uSq/1024 * (256+$uSq*(-128+$uSq*(74-47*$uSq)));
$deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)- $B/6*$cos2SigmaM*(-3+4*$sinSigma*$sinSigma)*(-3+4*$cos2SigmaM*$cos2SigmaM)));
$s = $b*$A*($sigma-$deltaSigma);
return $s/1000;
}
echo VincentyDistance($lat1,$lat2,$lon1,$lon2);