2010-03-09 10 views
8

Tôi đã tạo ra bảng MySQL sau để lưu trữ vĩ độ/kinh độ cùng với một tên cho mỗi điểm:điểm Query trong vòng bán kính được đưa ra trong MySQL

CREATE TABLE `points` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(128) NOT NULL, 
    `location` point NOT NULL, 
    PRIMARY KEY (`id`), 
    SPATIAL KEY `location` (`location`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; 

tôi đang cố gắng để truy vấn:

  • tất cả các điểm trong một bán kính n dặm của một điểm nhất định;
  • khoảng cách của mỗi điểm trở về từ các điểm nhất định

Tất cả các ví dụ tôi đã tìm thấy đề cập đến việc sử dụng một hình chữ nhật tối thiểu bounding (MBR) chứ không phải là bán kính. Bảng chứa khoảng 1 triệu điểm, vì vậy nhu cầu này cần phải hiệu quả nhất có thể.

Trả lời

3

Cảm ơn cả hai câu trả lời của bạn.

Tôi cuối cùng đã tìm thấy giải pháp tại http://www.movable-type.co.uk/scripts/latlong-db.html.

+0

Bạn đã làm gì để sửa lỗi này? Tôi đang đấu tranh với quyết định sử dụng MySQL 5.7 chức năng Spacial hoặc sử dụng công thức Haversine. – Jethro

2

Bán kính không thể lập chỉ mục hiệu quả. Bạn nên sử dụng hình chữ nhật bounding để nhanh chóng có được những điểm bạn có thể tìm kiếm, và sau đó lọc các điểm bên ngoài bán kính.

+0

Cảm ơn bạn đã trả lời. Giới hạn chỉ số bán kính chỉ là một vấn đề trong MySQL? Tôi tự hỏi liệu PostgreSQL có thể hoạt động tốt hơn không? Làm cách nào để loại bỏ các điểm khỏi hình chữ nhật bị ràng buộc không nằm trong bán kính? – gjb

+2

Không, đó là vấn đề chung. PostgreSQL làm cho nó dễ dàng hơn cho bạn, bởi vì bạn có thể hỏi một cách rõ ràng rằng điểm có được chứa trong một vòng tròn hay không và điều này sẽ sử dụng chỉ mục cũng như nó có thể, nhưng tôi tin rằng nó cũng sẽ chỉ sử dụng tìm kiếm hình chữ nhật trước. Tôi không thể thấy bất kỳ chức năng MySQL nào để làm điều đó, nhưng bạn có thể đơn giản tính toán khoảng cách giữa trung tâm và điểm. –

3

Đối với MySQL 5.7+

Với chúng tôi có bảng đơn giản sau đây,

create table example (
    id bigint not null auto_increment primary key, 
    lnglat point not null 
); 

create spatial index example_lnglat 
    on example (lnglat); 

Với các dữ liệu đơn giản sau đây,

insert into example (lnglat) 
values 
(point(-2.990435, 53.409246)), 
(point(-2.990037, 53.409471)), 
(point(-2.989736, 53.409676)), 
(point(-2.989554, 53.409797)), 
(point(-2.989350, 53.409906)), 
(point(-2.989178, 53.410085)), 
(point(-2.988739, 53.410309)), 
(point(-2.985874, 53.412656)), 
(point(-2.758019, 53.635928)); 

Bạn sẽ nhận được điểm trong một phạm vi nhất định của một điểm (lưu ý: chúng ta phải tìm kiếm bên trong một đa giác) với sự kết hợp sau đây của các chức năng st:

set @px = -2.990497; 
set @py = 53.410943; 
set @range = 150; -- meters 
set @rangeKm = @range/1000; 

set @search_area = st_makeEnvelope (
    point((@px + @rangeKm/111), (@py + @rangeKm/111)), 
    point((@px - @rangeKm/111), (@py - @rangeKm/111)) 
); 

select id, 
     st_x(lnglat) lng, 
     st_y(lnglat) lat, 
     st_distance_sphere(point(@px, @py), lnglat) as distance 
    from example 
where st_contains(@search_area, lnglat); 

Bạn sẽ thấy một cái gì đó như thế này kết quả là:

3 -2.989736 53.409676 149.64084252776277 
4 -2.989554 53.409797 141.93232714661812 
5 -2.98935 53.409906 138.11516275402533 
6 -2.989178 53.410085 129.40289289527473 

để tham khảo vào khoảng cách, nếu chúng ta loại bỏ các hạn chế kết quả cho kỳ thi điểm trông như thế này:

1 -2.990435 53.409246 188.7421181457556 
2 -2.990037 53.409471 166.49406509160158 
3 -2.989736 53.409676 149.64084252776277 
4 -2.989554 53.409797 141.93232714661812 
5 -2.98935 53.409906 138.11516275402533 
6 -2.989178 53.410085 129.40289289527473 
7 -2.988739 53.410309 136.1875540498202 
8 -2.985874 53.412656 360.78532732013963 
9 -2.758019 53.635928 29360.27797292756 

Note 1: lĩnh vực này được gọi là lnglat vì đó là thứ tự chính xác nếu bạn nghĩ về điểm như (x, y) và cũng là thứ tự nhất chức năng (như điểm) chấp nhận tham số

Lưu ý 2: bạn không thể tận dụng lợi thế của các chỉ mục không gian nếu bạn sử dụng vòng kết nối; cũng lưu ý rằng trường điểm có thể được thiết lập để chấp nhận các chỉ mục không gian nhưng không thể lập chỉ mục nếu nó không có giá trị (tất cả các trường trong chỉ mục được yêu cầu là không null).

Note 3: st_buffer được coi (theo tài liệu) là xấu đối với trường hợp sử dụng này

Chú giải 4: các chức năng trên (trong st_distance_sphere cụ thể) là tài liệu càng nhanh nhưng không nhất thiết siêu chính xác ; nếu dữ liệu của bạn siêu nhạy cảm với điều đó, hãy thêm một chút phòng lung tung vào tìm kiếm và thực hiện một số điều chỉnh chính xác cho tập kết quả

+0

Có lẽ tôi là sự hiểu lầm, nhưng bằng cách sử dụng 'st_contains' không phải là điều này vẫn sẽ được thực hiện các phép tính trong một mặt phẳng Descartes? Không phải hình cầu trái đất như mong muốn? – Twig

+0

Xin chào, tôi đang sử dụng mã của bạn ở trên, tôi có một câu hỏi, @rangeKm/111 có nghĩa là gì? 111 là gì? –