Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Tìm kiếm địa lý (Khoảng cách) trong PHP / MySQL (Hiệu suất)

Tính toán hộp giới hạn để chọn một tập hợp con của các hàng trong mệnh đề WHERE của truy vấn SQL của bạn, để bạn chỉ thực hiện phép tính khoảng cách đắt tiền trên tập hợp con các hàng đó thay vì so với toàn bộ 200 bản ghi trong bảng của bạn. Phương pháp được mô tả trong bài viết về Loại có thể di chuyển này (với các ví dụ về mã PHP). Sau đó, bạn có thể đưa phép tính Haversine vào truy vấn của mình với tập hợp con đó để tính toán khoảng cách thực tế và nhân tố trong mệnh đề HAVING tại thời điểm đó.

Đó là hộp giới hạn giúp hiệu suất của bạn, vì nó có nghĩa là bạn chỉ thực hiện tính toán khoảng cách đắt tiền trên một tập hợp con dữ liệu nhỏ của mình. Đây thực sự là phương pháp mà Patrick đã đề xuất, nhưng liên kết Loại có thể di chuyển có các giải thích sâu rộng về phương pháp này, cũng như mã PHP mà bạn có thể sử dụng để tạo hộp giới hạn và truy vấn SQL của mình.

CHỈNH SỬA

Nếu bạn không nghĩ rằng hasrsine là đủ chính xác, thì cũng có công thức Vincenty.

//  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);


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Một MySQL DELETE thành công trả về điều gì? Làm cách nào để kiểm tra xem XÓA có thành công không?

  2. Sử dụng lớp cơ sở dữ liệu Django bên ngoài Django?

  3. MySQL ROUND () Hàm - Làm tròn một số đến một số vị trí thập phân cho trước

  4. Cài đặt Máy chủ Web trong FreeBSD 6.0 với Apache 2.2, MySQL 5.0 và PHP 5 - Phần 3

  5. MySQL Liệt kê tất cả các thủ tục