2013-05-24 12 views
0

У меня есть MySQL-процедура, которая получает записи в радиусе 50 миль при передаче Широта и долготы с использованием уравнения Хаверсина.Поиск по радиусу Zipcode с POINT Столбец

Несмотря на то, что это работает отлично и довольно быстро (учитывая, что он просматривает записи 82k), я думаю, что я могу получить лучшую производительность, создав аналогичную процедуру, используя столбец POINT.

Так, в моей таблице я создал дополнительный столбец Location, дал ему тип данных POINT, обновил свои данные, чтобы передать широчайшие & LON к Location колонку. Данные верны, и это хорошо., И добавил Spatial Index

Вопрос заключается в том, как я могу преобразовать следующий запрос использовать Location колонку, вместо lat и lon колонн.

SET @LAT := '37.953'; 
SET @LON := '-105.688'; 

SELECT DISTINCT 
BPZ.`store_id`,   
3956 * 2 * ASIN(SQRT(POWER(SIN((@LAT - abs(Z.`lat`)) * pi()/180/2),2) + COS(@LAT * pi()/180) * COS(abs(Z.`lat`) * pi()/180) * POWER(SIN((@LON - Z.`lon`) * pi()/180/2), 2))) as distance, 
c.`name`,c.`address`,c.`city`,c.`state`,c.`phone`,c.`zip`,c.`premise_type` 
FROM 
`zip_codes` as Z, 
`brand_product_zip` as BPZ 
LEFT JOIN `customers` c ON c.`store_id` = BPZ.`store_id` 
WHERE 
BPZ.`zip` = Z.`zip` 
AND 
3956 * 2 * ASIN(SQRT(POWER(SIN((@LAT - abs(Z.`lat`)) * pi()/180/2),2) + COS(@LAT * pi()/180) * COS(abs(Z.`lat`) * pi()/180) * POWER(SIN((@LON - Z.`lon`) * pi()/180/2), 2))) <= 50 
ORDER BY 
distance LIMIT 20 

Я понимаю, что это было предложено ранее, однако, все, что я вижу точки для расчетов, основанных на lat и lon и не POINT колонке

Обновлено Код:

SET @lat = 41.92; 
SET @lon = -72.65; 
SET @kmRange = 80.4672; -- = 50 Miles 

SELECT *, (3956 * 2 * ASIN(SQRT(POWER(SIN((@lat - abs(`lat`)) * pi()/180/2),2) + COS(@lat * pi()/180) * COS(abs(`lat`) * pi()/180) * POWER(SIN((lon - `lon`) * pi()/180/2), 2)))) as distance 
FROM `zip_codes` 
WHERE MBRContains(LineString(Point(@lat + @kmRange/111.1, @lon + @kmRange/(111.1/COS(RADIANS(@lat)))), Point(@lat - @kmRange/111.1, @lon - @kmRange/(111.1/COS(RADIANS(@lat))))), `Location`) 
Order By distance 
LIMIT 20 
+0

если вы можете геокодировать вам данные в точку, как о только собирается после скажем, LIMIT 5 или тому подобное по вашему запросу, когда вы идете после нескольких близких точек. – Drew

+0

действительно не уверен, что вы говорите и как это относится к моему вопросу. Мне нужно 20 записей назад, поэтому «LIMIT 20» – Kevin

+0

о, я даже не смотрел на ваш лимит, извините. поэтому у вас есть данные точки в вашем db. вы создаете и индексируете на нем, и это фокус вашего предложения where в select (не lat и longitude) – Drew

ответ

2

У вас посмотрел на решения гильбертовых кривых? Пространственный индекс не дает точное решение? , С пространственного индекса тузд можно использовать mbrcontains:

CREATE TABLE lastcrawl (id INT NOT NULL PRIMARY KEY, pnt POINT NOT NULL) ENGINE=MyISAM; 

INSERT 
INTO lastcrawl 
VALUES (1, POINT(40, -100)); 

SET @lat = 40; 
SET @lon = -100; 

SELECT * 
FROM lastcrawl 
WHERE MBRContains 
       (
       LineString 
         (
         Point 
           (
           @lat + 10/111.1, 
           @lon + 10/(111.1/COS(RADIANS(@lat))) 
           ), 
         Point (
           @lat - 10/111.1, 
           @lon - 10/(111.1/COS(RADIANS(@lat))) 
           ) 
         ), 
       pnt 
       ); 

посмотреть здесь: MySQL - selecting near a spatial point. Здесь: http://www.drdobbs.com/database/space-filling-curves-in-geospatial-appli/184410998

+0

. Могу ли я использовать это как столбец 'distance'? Кроме того, для чего нужен 111,1? Это потенциальный радиус километра? – Kevin

+0

nah, думаю, я не могу использовать его в качестве столбца расстояния ... – Kevin

+0

111km примерно градус долгота: http://stackoverflow.com/questions/1006654/fastest-way-to-find-distance-between-two -lat-длинные-очков. В принципе да, он получает расстояние и сортирует его. – Bytemain

1

В статье Nearest-location finder for MySQL подробно изложены различные варианты и лучший выбор для использования с Spatial Extensions starting with MySQL 5.6.

Из статьи, это списки образца запроса почтовых индексов в радиусе 50 миль от заданных координат (42.81, -70.81):

SELECT zip, primary_city, 
     latitude, longitude, distance_in_mi 
    FROM (
SELECT zip, primary_city, latitude, longitude,r, 
     69.0 * DEGREES(ACOS(COS(RADIANS(latpoint)) 
       * COS(RADIANS(latitude)) 
       * COS(RADIANS(longpoint) - RADIANS(longitude)) 
       + SIN(RADIANS(latpoint)) 
       * SIN(RADIANS(latitude)))) AS distance_in_mi 
FROM zip 
JOIN (
     SELECT 42.81 AS latpoint, -70.81 AS longpoint, 50.0 AS r 
    ) AS p 
WHERE latitude 
    BETWEEN latpoint - (r/69) 
     AND latpoint + (r/69) 
    AND longitude 
    BETWEEN longpoint - (r/(69 * COS(RADIANS(latpoint)))) 
     AND longpoint + (r/(69 * COS(RADIANS(latpoint)))) 
) d 
WHERE distance_in_mi <= r 
ORDER BY distance_in_mi; 
Смежные вопросы