Проблемы производительности SQL Cross Apply - PullRequest
1 голос
/ 01 февраля 2012

В моей базе данных есть каталог из 2000 мест, разбросанных по всей территории США, с информацией о почтовом индексе (которую я привязал к координатам lon / lat).

У меня также есть табличная функция, которая принимает два параметра (ZipCode & Miles), чтобы вернуть список соседних почтовых индексов (исключая тот же искомый почтовый индекс)

Для каждого местоположения я пытаюсь получить идентификаторы соседнего местоположения. Таким образом, если у местоположения № 4 есть три соседних местоположения, выходные данные должны выглядеть следующим образом:

  1. 4 5
  2. 4 24
  3. 4 137

То есть местоположения 5, 24 и 137 находятся в пределах X миль от местоположения 4.

Первоначально я пытался использовать перекрестное наложение с моей функцией следующим образом:

SELECT A.SL_STORENUM,A.Sl_Zip,Q.SL_STORENUM FROM tbl_store_locations AS A
CROSS APPLY (SELECT SL_StoreNum FROM tbl_store_locations WHERE SL_Zip in (select zipnum from udf_GetLongLatDist(A.Sl_Zip,7))) AS Q 
WHERE A.SL_StoreNum='04'

Однако это длилось более 20 минут безрезультатно, поэтому я отменил его. Я попробовал жесткое кодирование в почтовом индексе, и он сразу же возвратил список

SELECT A.SL_STORENUM,A.Sl_Zip,Q.SL_STORENUM FROM tbl_store_locations AS A
CROSS APPLY (SELECT SL_StoreNum FROM tbl_store_locations WHERE SL_Zip in (select zipnum from udf_GetLongLatDist('12345',7))) AS Q 
WHERE A.SL_StoreNum='04'

Каков наиболее эффективный способ составления списка ближайших мест? Учитывая, что в качестве примера я использовал «04», я хочу провести анализ для 2000 местоположений.

«udf_GetLongLatDist» - это функция, которая использует математические вычисления для вычисления расстояния между двумя географическими координатами и возвращает список почтовых индексов с расстоянием> 0. Ничего особенного в этом нет.

Ответы [ 3 ]

1 голос
/ 01 февраля 2012

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

where latitude >= @targetLat - (@miles/69.2) and latitude <= @targetLat + (@miles/69.2)

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

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

1 голос
/ 01 февраля 2012

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

select zip2 from zipprecalc where zip1 = '12345' and distance <=10
0 голосов
/ 01 февраля 2012

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

Однако рефакторинг запроса может быть следующим ...

SELECT
  A.SL_STORENUM, A.Sl_Zip, C.SL_STORENUM
FROM
  tbl_store_locations                 AS A
CROSS APPLY
  dbo.udf_GetLongLatDist(A.Sl_Zip,7)  AS B
INNER JOIN
  tbl_store_locations                 AS C
    ON C.SL_Zip = B.zipnum
WHERE
  A.SL_StoreNum='04'

Такжепроизводительность CROSS APPLY значительно улучшится, если вы сможете убедиться, что udf является INLINE, а не MULTI-STATEMENT.Это позволяет развернуть файл udf (как в макросе) для более чистого плана выполнения.

Это также позволит вам вернуть дополнительные поля из файла udf.Затем оптимизатор может включить или исключить эти поля из плана в зависимости от того, действительно ли вы их используете.Такой пример мог бы включать SL_StoreNum, если он легко доступен из запроса в формате udf, и, таким образом, убрать необходимость последнего соединения ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...