2011-01-18 45 views
9

Tôi muốn lưu trữ giá trị vĩ độ và kinh độ của các địa điểm trong bảng cơ sở dữ liệu mysql. Với tương lai trong tâm trí tôi sẽ muốn để có thể tìm thấy những nơi này trong một bán kính nhất định của một địa điểm cụ thể. Có nói rằng, những gì datatypes tôi nên lưu trữ các vĩ độ và kinh độ giá trị trong? Xin bạn có thể cung cấp cho tôi với một kịch bản tạo bảng cho các cột như sau:Thiết lập bảng vĩ độ và kinh độ của MySQL

place_id | lat | long 

Có lẽ một cột tôi đang thiếu trong bảng trên mà sẽ cung cấp cho tôi với thêm thông tin mà tôi không thể nhìn thấy tôi cần tại thời điểm hiện tại?

Cảm ơn bạn đã được trợ giúp.

+0

có thể trùng lặp [Loại dữ liệu lý tưởng để sử dụng khi lưu trữ vĩ độ/kinh độ trong cơ sở dữ liệu MySQL là gì?] (Http://stackoverflow.com/questions/159255/what-is-the-ideal-data-type -to-use-khi-lưu-latitude-longitudes-in-a-mysql) – Gajus

Trả lời

21

Bạn nên lưu trữ các điểm trong một cột singe của datatype Point mà bạn có thể chỉ với một chỉ số SPATIAL (nếu loại bảng của bạn là MyISAM):

CREATE SPATIAL INDEX sx_place_location ON place (location) 

SELECT * 
FROM mytable 
WHERE MBRContains 
       (
       LineString 
         (
         Point($x - $radius, $y - $radius), 
         Point($x + $radius, $y + $radius) 
         ) 
       location 
       ) 
     AND Distance(Point($x, $y), location) <= $radius 

này sẽ cải thiện đáng kể tốc độ của các truy vấn như " tìm tất cả trong một bán kính nhất định ".

Lưu ý rằng tốt hơn nên sử dụng đồng bằng TM tọa độ metric (hướng đông và hướng bắc) thay vì cực (vĩ độ và kinh độ). Đối với bán kính nhỏ, chúng đủ chính xác và các phép tính được đơn giản hóa rất nhiều. Nếu tất cả các điểm của bạn nằm trong một bán cầu và cách xa các cực, bạn có thể sử dụng một kinh tuyến trung tâm duy nhất.

Bạn vẫn có thể sử dụng tọa độ cực của khóa học, nhưng các công thức để tính MBR và khoảng cách sẽ phức tạp hơn.

+1

Tất cả các bảng của tôi sử dụng InnoDB khi tôi sử dụng các khóa ngoại. Nó không phải là một vấn đề để có bảng trong cả hai InnoDB và MyISAM? – Martin

+0

@Martin: 'MyISAM' không giao dịch và bạn không thể sử dụng các ràng buộc' NGOẠI TỆ 'trên đó. Đối với các truy vấn 'SELECT' duy nhất, không có vấn đề gì với việc trộn các bảng của các kiểu khác nhau. – Quassnoi

+0

Có, tôi hiểu rằng các khóa nước ngoài không hoạt động trong MyISAM tuy nhiên nếu tôi có thêm một bảng cho các tọa độ và có như MyISAM và tất cả các bảng khác của tôi là InnoDB không phải là một vấn đề? – Martin

0

Tôi đã đào vài giờ qua tấn chủ đề và không thể tìm thấy truy vấn nào, trả về các điểm trong bán kính, được xác định theo km. Tuy nhiên, ST_Distance_Sphere thực hiện, máy chủ là MariaDB 5.5, không hỗ trợ ST_Distance_Sphere().

Managed để có được một cái gì đó làm việc, vì vậy đây là giải pháp của tôi, tương thích với Học thuyết 2.5 và Giáo Lý CrEOF Thư viện không gian:

$sqlPoint = sprintf('POINT(%f %f)', $lng, $lat); 

    $rsm = new ResultSetMappingBuilder($this->manager); 
    $rsm->addRootEntityFromClassMetadata('ApiBundle\\Entity\\Place', 'p'); 

    $query = $this->manager->createNativeQuery(
     'SELECT p.*, AsBinary(p.location) as location FROM place p ' . 
     'WHERE (6371 * acos(cos(radians(Y(ST_GeomFromText(?)))) ' . 
     '* cos(radians(Y(p.location))) * cos(radians(X(p.location)) ' . 
     '- radians(X(ST_GeomFromText(?)))) + sin(radians(Y(ST_GeomFromText(?)))) * sin(radians(Y(p.location))))) <= ?', 
     $rsm 
    ); 

    $query->setParameter(1, $sqlPoint, 'string'); 
    $query->setParameter(2, $sqlPoint, 'string'); 
    $query->setParameter(3, $sqlPoint, 'string'); 
    $query->setParameter(4, $radius, 'float'); 

    $result = $query->getResult(); 

Giả sử lng và lat là XY của điểm cố định, Place là những thực thể có một trường "vị trí" loại POINT. Tôi không thể sử dụng DQL trực tiếp do các vấn đề với ràng buộc param của MySQL, đó là lý do tại sao truy vấn gốc cấp thấp. Rsm được yêu cầu để ánh xạ kết quả vào đối tượng thực thể. Có thể sống mà không có nó, mặc dù.

Hãy sử dụng nó. Tôi hy vọng nó sẽ giúp bạn tiết kiệm thời gian.

Các vấn đề liên quan