Как оптимизировать мой SQL на сервере? - PullRequest
0 голосов
/ 02 октября 2009

Я хотел бы знать, как оптимизировать следующий SQL-запрос, чтобы ускорить загрузку моего сервера и снизить нагрузку на него?

Мне нужно рассчитать радиус-расстояние для почтового индекса США, чтобы получить результат, например, в 50 милях от определенного почтового индекса (с использованием широты и долготы для расчета) и для получения количества других данных (например, других почтовых индексов) из моей базы данных.

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

SELECT count(*)
FROM
( SELECT b.ID, ROUND((acos(sin(3.142/180*32.91336) * sin(3.142/180*z.latitude) + cos(3.142/180*32.91336) * cos(3.142/180*z.latitude) * cos((3.142/180*z.longitude) - (3.142/180*-85.93836))) * 3959),2) AS distance
  FROM zipcode2business.accountants b LEFT JOIN zipcodeworld.storelocator_us z ON b.ZIPCODE = z.ZIP_CODE
  WHERE z.latitude != 32.91336 AND z.longitude != -85.93836
  AND b.STATE='AL'
  HAVING distance between 0 AND 50) 
as total;

Надеюсь, я не сделал неправильно, он отображает правильный результат (350 строк), но мне нужен оптимизированный способ его запуска, потому что этот SQL дал мне высокую загрузку ЦП для загрузки. Когда я делаю EXPLAIN для этого запроса, он отображает следующее:

+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+
| id | select_type | table | type   | possible_keys    | key     | key_len | ref                        | rows | Extra                        |
+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+
| 1 | PRIMARY      | NULL  | NULL   | NULL             | NULL    | NULL    |        NULL                | NULL | Select tables optimized away |
| 2 | DERIVED      | b     | ref    | ZIPCODE,STATE    | STATE   | 4       |                            | 3900 | Using where                  |
| 2 | DERIVED      | z     | eq_ref | PRIMARY,LAT_LONG | PRIMARY | 9       | zipcode2business.b.ZIPCODE | 1    | Using where                  |
+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+
3 rows in set (0.20 sec)

Теперь, из вышеприведенного объяснения, «Выбрать оптимизированные таблицы» в EXTRA - это хорошо? Пожалуйста, покажите мне один наиболее совершенный оптимизационный SQL для выполнения этого запроса.

Ответы [ 3 ]

1 голос
/ 02 октября 2009

Сам по себе SQL выглядит нормально, большая часть процессорного времени должна быть потрачена на математику ... Есть два пути оптимизации

  • упрощение формул
  • Ранняя фильтрация строк ("обрезка") на основе еще более простого вычисления

У меня нет времени на полную информацию, но вот общая идея:
Это приблизительное расстояние от эталонного местоположения ZipCode и других местоположений, с дешевым (с точки зрения процессора) вычислением, и только выполнение полной математики (с лучшей формулой, чем в оригинале) запрос), для местоположений, которые находятся ниже 50 миль (+ небольшая дополнительная, чтобы учесть возможную недооценку).

Оценка расстояния и обрезки
Вычислим, раз , расстояние expessed в милях, соответствующее одному градусу широты и один градус долготы, от места ссылки ZipCode; Назовите эти MpDLat и MpDLong. Возможно, мы вычислим дробное значение степени, что соответствует нашему целевому радиусу от опорного местоположения; Назовите эти Dp50Lat и Dp50Long. Тогда работа с [абсолютной величине] разности широт и долгот между, по отношению к опорному местоположению и отфильтровать местоположения, для которого это расстояние в одном направлении (лат или длинный) превышает наш предел. то есть что-то вроде следующего

WHERE .... (some other condidtions....) 
   AND (abs(z.latitude - 32.91336) * MpDLat) < 50 
   AND (abs(z.longitude + 85.93836) * MpDLong) < 50 
--or, if we got by the Dp50 values
WHERE .... (some other condidtions....) 
   AND (abs(z.latitude - 32.91336)  < Dp50Lat
   AND (abs(z.longitude + 85.93836) < Dp50Long 

Расчет расстояния (для тех мест, которые не легко фильтруются)
В зависимости от требуемого уровня точности, может быть приемлемо придерживаться коэффициентов MpD (я предполагаю, что погрешности составляют менее мили или около того, для расстояний порядка 50 миль в пределах континентальной части США). Тогда расстояния будут рассчитываться как: Sqrt ((z.latitude - 32.91336) ^ 2 + (z.longitude + 85.93836) ^ 2 или, если мы заинтересованы только в том, чтобы отфильтровать их без необходимого расстояния как такового, мы можем работать с квадратами, т.е. ... ГДЕ (z.latitude - 32,91336) ^ 2 + (z.lonitude + 85,93836) ^ 2 <2500 - 2509 - это 50 ^ 2 </p>

Я предполагаю, что этот тип аппроксимации является приемлемым, поскольку допускаются гораздо большие ошибки, принимая во внимание тот факт, что расстояние по дорогам (что, вероятно, в конечном итоге и является желаемым) редко совпадает с расстоянием "как в мухи ';-) Я могу рассчитать потерю точности в худшем случае (но опять же, сейчас нет времени ...)

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

Вариации на выше
Рассмотренные выше идеи могут быть реализованы различными способами, например, с использованием временных таблиц SQL или различных конструкций для запроса (запросов) и т. Д.

0 голосов
/ 08 октября 2009

вы можете выбрать расчет расстояния во временной таблице и удалить HAVING из вашего SQL, затем выполнить 2-й SELECT WHERE dist <= 50 </p>

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

0 голосов
/ 02 октября 2009

Нужно ли выполнять все эти вычисления на сервере sql? Я обычно стараюсь использовать SQL только для базового CRUD с данными, тогда все другие вычисления выполняются вне SQL. Возможно, вы захотите попытаться получить данные, на которых вы основываете свои расчеты, а затем выполнить фактический расчет с тем, что извлекает данные.

...