Как оптимизировать SQL-запрос с вычислением расстояния по долготе и широте? - PullRequest
3 голосов
/ 22 июня 2010

У меня есть таблица с такой структурой:

table name: shop

id_shop      int(10)
name         varchar(200)
latitude     double
longitude    double

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

Мой текущий запрос:

SELECT *
  FROM `shop` AS `s`
 WHERE
      (
        ( 6371
        * ACOS(
            SIN( RADIANS( latitude ) )
          * SIN( RADIANS( 53.5353010379 ) )
          + COS( RADIANS( latitude ) )
          * COS( RADIANS( 53.5353010379 ) )
          * COS( RADIANS( 14.7984442616 ) - RADIANS( longitude ) )
          )
        )
        <= 25
      )

плюс некоторые JOIN LEFT для некоторых данных.

Есть ли способ оптимизировать этот запрос?С объединениями это занимает около 13 мсек.

Мне нужно добавить сюда также LIMIT и COUNT(*) для общего количества магазинов для разбивки на страницы.

Ответы [ 2 ]

5 голосов
/ 22 июня 2010

Вот несколько идей, некоторые из которых могут не применяться в зависимости от вашей конкретной ситуации.

  1. Вы можете выполнить преобразование широты и долготы в радианы и сохранить их в строке.Это позволит сэкономить на стоимости этих вычислений (фактически, при хранении данных они будут начислены один раз).
  2. Если ваша таблица очень большая, вы можете использовать простое линейное вычисление расстояния, а не формулу Хаверсинса, чтобы ограничитьрезультаты, к которым вы применяете формулу Хаверсинса.
  3. Если у вас есть другие данные в таблице, которые будут служить хорошим первым фильтром (страна / регион / и т. д.), вы можете применить их в первую очередь.
  4. Вы можете изменить порядок своих объединений, чтобы они применялись после фильтра расстояний, чтобы избежать затрат на объединение для данных, которые не соответствуют требованиям.
5 голосов
/ 22 июня 2010

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

Может быть, еще немного сбрить, сохраняя SIN (RADIANS (широта)) и COS (RADIANS (широта)) при первом заполнении строки тоже ...

Я предполагаю, что вы делаете много, много вычислений "ближайшего к Х" со временем - это то, что люди обычно делают, когда сталкиваются с этими вычислениями - и предварительный расчет того, что вы можете, обычно является первымчто попробовать.

...