Самый быстрый способ (и наиболее оптимизированный) для расчета и сортировки пользователей по возрастанию расстояния по почтовому индексу - PullRequest
1 голос
/ 07 марта 2011

У меня есть система, которая будет возвращать всех пользователей из базы данных и упорядочивать результаты по минимальному расстоянию от ссылочного почтового индекса.

Например: пользователь заходит на сайт, вводит почтовый индекс, и онверните ему всех остальных пользователей, которые находятся ближе к его почтовому индексу (в порядке возрастания)

Как я делаю это сейчас и почему это проблема?

Система содержит большечем 30 миллионов пользователей и их почтовые индексы.Я извлекаю всех пользователей в определенном штате и городе (сужает набор данных примерно до 10000).

Вот где на самом деле возникает проблема.Теперь все результаты, отправленные MySQL (10 000) строк в PHP, отправляются в библиотеку калькуляторов почтовых индексов, которая вычисляет это расстояние между базовым почтовым индексом и почтовым индексом пользователя - 10000 раз.Затем упорядочивает результат по ближайшему почтовому индексу.

Как видите, это очень плохо оптимизированный код.И 10000 записей пройдены дважды.Не говоря уже о количестве оперативной памяти, которую каждый httpd-процесс занимает только для передачи данных туда и сюда mysql.

Что я хотел бы спросить здесь у гуру, что в любом случае можно оптимизировать?

У меня есть несколько собственных идей, но я не уверен, насколько они эффективны.

Попробуйте выполнить весь расчет и упорядочение почтового индекса в самом mysql.и верните нумерованное количество строк.Для этого мне нужно переместить расстояние между логикой вычисления почтового индекса в хранимую процедуру.Таким образом, я предотвращаю обработку 10000 записей в PHP.Тем не менее, проблема все еще существует.Мне не нужно рассчитывать расстояние для уже рассчитанных почтовых индексов (для 2 пользователей, имеющих одинаковый почтовый индекс).

Во-вторых, как мне упорядочить строки в MySQL, используя хранимую процедуру?

Что вы, ребята, думаете?Это хороший способ?Могу ли я ожидать повышения производительности с помощью этого?У вас есть другие предложения?

Я знаю, что этот вопрос огромен, и я действительно ценю время, которое вы потратили на чтение до конца.Мне бы очень хотелось услышать ваши мысли по этому поводу.

Ответы [ 3 ]

1 голос
/ 07 марта 2011

Поскольку я не слишком знаком с PHP или MySQL, я могу дать только некоторые базовые советы, но они должны помочь.Это также предполагает, что у вас нет прямого способа взаимодействия с библиотекой zip из MySQL.

Во-первых, сомнительно, что у вас есть 10k почтовых индексов в городе, возьмите существующий запрос и выполните что-то вроде

SELECT DISTINCT ZipCode FROM Users WHERE ...

Это, вероятно, вернет максимум несколько десятков почтовых индексов без дубликатов.Запустите это через вашу библиотеку почтового индекса.Сама эта библиотека, вероятно, является источником медлительности, поскольку она должна искать почтовые индексы и делать кучу необычных триггеров, чтобы получить реальное расстояние.Возьмите результаты этого и вставьте его во временную таблицу, указав только почтовый индекс и расстояние.

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

Это должно дать вам довольно большое ускорение.Вы можете делать все, что вам нужно, во втором запросе после вычисления результатов.И больше никаких циклов по 10 тыс. Строк.

1 голос
/ 07 марта 2011

Я предлагаю вам сузить диапазоны широты и долготы, прежде чем вычислять точное расстояние для целей фильтрации и сортировки.

Я имею в виду, что если вы выполните полное сканирование таблицы и вычислите расстояния для всех почтовых индексов в базе данных относительно вашей контрольной точки, это будет очень медленно.

Вместо этого фильтруйте почтовый индекс по близости. Я имею в виду, если у вас широта 10 и долгота 20, сначала вычислите максимальный угловой диапазон для желаемой близости. Допустим, вы хотите расстояние 10 миль. Это может привести к 0,15 градусов. Поэтому вам нужно отфильтровать почтовые индексы первой широты между 10-0,15 и 10 + 0,15 и долготы между 20-0,15 и 20 + 0,15.

Только после этого вы включаете условие точного расстояния в условие SQL-запроса. Это будет намного быстрее, поскольку вы больше не будете выполнять полное сканирование и в конечном итоге сможете использовать индексы диапазона для полей долготы и широты.

Чтобы перевести мили в градусы, найдите узкий диапазон, имейте в виду, что Земля имеет приблизительно 25 000 миль по периметру, разделив 25000 на 360 градусов, что дает 70 миль на градус. Если вам нужен диапазон в 10 миль, ваш диапазон в градусах будет не более 0,15 градусов.

Имейте в виду, что эти вычисления не точны (Земля не совсем хорошо округлена), но это не важно. Важно то, что вы найдете значение диапазона градусов, которое превышает действительно точное значение.

0 голосов
/ 07 марта 2011

Если вы можете получить широту и долготу для всех почтовых индексов в MySQL или иметь простой способ выбрать широту и долготу для вашего базового почтового индекса и ввести их в свой запрос MySQL, то вы можете заказать 10k пользователей по расстоянию внутриMySQL.Существует очень похожий вопрос и ответ здесь , который дает вам правильную математику для функции расстояния.Возможно, вы также захотите изучить Пространственные расширения Mysql , которые позволили бы вам вставлять и индексировать свои значения широты / долготы как данные 2D POINT.

...