LINUX.ORG.RU

Оптимизация поиска ближайших zip кодов по географическим координатам


0

1

Имеется таблица

CREATE TABLE `zips` (
  `id` char(5) NOT NULL,
  `type` varchar(255) NOT NULL,
  `city_id` bigint(20) unsigned NOT NULL,
  `timezone_id` bigint(20) unsigned NOT NULL,
  `area_codes` varchar(255) NOT NULL,
  `latitude` decimal(10,8) NOT NULL,
  `longitude` decimal(11,8) NOT NULL,
  `estimated_population` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `latitude` (`latitude`),
  KEY `longitude` (`longitude`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

содержащая 42,153 записи.

В целях оптимизации поиска расстояний появилась идея создать таблицу

CREATE TABLE `zip_distance` (
  `zip1` char(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  `zip2` char(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  `distance` decimal(6,2) DEFAULT NULL,
  UNIQUE KEY `zips_uni` (`zip1`,`zip2`),
  KEY `distance` (`distance`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

и просчитать расстояние для каждой пары zip кодов заранее что бы не приходилось пересчитывать его каждый раз при поиске в продакшене.

Получается 42,153 * 42,153 == 1,776,875,409 записей. Что бы для начала прикинуть создал процедуру которая просто добавляет все пары zip кодов в zip_distance:

begin
declare done int default false;
declare zip1 char(5);
declare zip2 char(5);

declare cur1 cursor for select id from zips order by id asc;
declare cur2 cursor for select id from zips order by id asc;

declare continue handler for not found set done = true;

open cur1;
open cur2;

read_loop: loop
fetch cur1 into zip1;
fetch cur2 into zip2;

if done then
  leave read_loop;
end if;

insert into zip_distance set zip1 = zip1, zip2 = zip2;
end loop;

close cur1;
close cur2;
end

Результат печальный. Судя по скорости работы процедуре потребуется около года на моём железе.

Можно ли как то оптимизировать что бы просчитать всё максимум за один день? Может быть есть готовая таблица с расстояними? Так же не известно насколько быстрым будет поиск по таблице с почти 2 биллионами записей, возможно ещё медленней и смысла в этом всём вообще нет.

Ответ на: комментарий от Apple-ch

Тебя жестоко обманули. Прекрати засирать тему этим флудом.

tux2015
() автор топика

Если тебе нужны только ближайшие координаты, то зачем хранить растояния между всеми точками? Храни только между ближайшими.

Во второй таблице храни zip1 и zip2 как foreign key. - с integer быстрее работает. Добавь туда индекс по первому полю zip1 и unique index на 2 поля (zip1, zip2).

В приложении соответственно будешь делать запрос по индексу zip1 - и будешь получать, допустим, 20 строк результатов с ближайшими zip2.

pi11 ★★★★★
()
Ответ на: комментарий от bvn13

Т.е. в транзакции

BEGIN;
INSERT ...
INSERT ...
...........
INSERT ...
COMMIT;

Будет быстрее?

Я пробовал сделать

INSERT (zip1, zip2) VALUES (..., ...), (..., ...), ..., (..., ...);


Но когда запускал "source file.sql" получал через некоторое время сообщение:

ERROR 2006 (HY000): MySQL server has gone away

Сколько максимум может быть значений после VALUES?
tux2015
() автор топика

Вариант 1. Тупой.

Для данной точки X,Y задаёшь квадрат X+-N, Y+-M, выбираешь координаты, которые в него попали и уже для них считаешь расстояния.

Вариант 2. Поиск через иерархию регионов.

Пусть вся карта — это большой квадрат A. Он делится на 4 квадрата B1, B2, B3, B4, и т.д. Так пилишь до нужной тебе точности. Потом проставляешь всем кодам их регион. Дальше для заданной точки ищешь по иерархии нужный регион и сравниваешь с точками из него (если нужно — поднимаешься на уровень вверх). Учитывая, что точка может лежать на краю региона, хранишь в нём ссылки на 8 соседних и можешь и в них искать. Расстояние от точки до центра региона и сектор можно проставить сразу и использоваать как критерий для выбора соседних регионов.

aidan ★★★★
()

Кто-нибудь в теме оценивал с этой точки зрения геофункции Postgre? Насколько быстро работает

ORDER BY ST_Distance(location, point)
?

KRoN73 ★★★★★
()
Ответ на: комментарий от aidan

И как это всё (вариант 2) реализовать в одном SQL запросе? Даже не знаю с чего начать...

tux2015
() автор топика

просчитать расстояние для каждой пары zip кодов заранее что бы не приходилось пересчитывать его каждый раз при поиске в продакшене.

А если заполнять базу на продакшене постепенно - по мере обращения, при запросе расстояний какой то пары zip-кодов вычислять расстояние и добавлять запись в базу. При следующем обращении к этой паре значение брать уже из базы.

anonymous
()

Не рано ли ты оптимизируешь? Ты уже прогнал существую систему на расчетной нагрузке и тебя не устроили результаты? Или просто от нефиг делать?

vostrik ★★★☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.