Какой самый быстрый способ расчета и возврата ближайших элементов в таблице B из таблицы A в пределах установленного радиуса - PullRequest
0 голосов
/ 13 февраля 2019

У меня очень большое количество координат широты / долготы в Таблице 1, а также в Таблице 2. Например, предположим, что в обеих таблицах есть 100 000 координат.Мне нужно вернуть ближайшую пару координат в таблице 2 из таблицы 1, если они находятся в пределах установленного минимального расстояния (скажем, 100 метров) для каждого уникального элемента из таблицы 1 (до 100 000 элементов, но затем отбрасываютсядо 100 метров это мой ожидаемый выход).

Я довольно хорошо знаком с частями MSSQL Geometry и Geography и традиционно подхожу к следующему примерно так:

Select
Table1ID = T1.ID,
Table2ID = T2.ID,
Distance = T1.PointGeog.STDistance(T2.PointGeog),
Keep = 0
into #Distance 
From #Table1 T1
   cross join #Table2 T2
where T1.PointGeog.STDistance(T2.PointGeog) <= 100

, который возвращает все элементы из Table2, которые находятся в пределах 100метров Table1

Затем, чтобы ограничиться только самыми близкими предметами, я мог бы:

Update #Distance
 set Keep = 1
from #Distance D 
   inner join 
   (select shortestDist = min(Distance), Table1ID from #Distance GROUP BY 
    Table1ID) A
    on A.ID = D.Table1ID and A.shortestDist = D.Distance

и затем удалить все, где хранится <> 1

Это работает, однакоэто займет абсолютно навсегда.Перекрестное соединение создает абсурдное количество вычислений, которые должен выполнить SQL, что приводит к ~ 9-минутным запросам на MSSQL 2016. Я могу ограничить диапазон частей Таблицы 1 и Таблицы 2, которые я сравниваю с некоторыми критериями, но на самом деле это не так.много.Я просто действительно не уверен, как я мог сделать процесс быстрее.В конечном итоге мне просто нужно: ближайший предмет, расстояние от Т2 до Т1.

Я поиграл с несколькими различными решениями, но я хотел посмотреть, есть ли у сообщества SO какие-либо дополнительные идеи о том, как мне лучше оптимизировать что-то подобное.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Я поиграл с новой опцией, и я думаю, что это самый быстрый способ расчета - около 3 минут.

Я изменил Table1 на:

select
ID,
PointGeog,
Buffer = PointGeom.STBuffer(8.997741566866716e-4)
into #Table1

, где буфер 100/111139 (преобразовать градусы в метры)

, а затем

if object_id('tempdb.dbo.#Distance') is not null
drop table #Distance 
Select 
T1ID = T1.ID,
T1Geog = T1.PointGeog,
T2ID = T2.ID,
T2Geog = T2.PointGeog,
DistanceMeters = cast(null as float),
DistanceMiles = cast(null as float),
Keep = 0
Into #Distance
From #Table1 T1
    cross join #Table2 T2
Where T1.Buffer.STIntersects(T2.PointGeom) = 1

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

0 голосов
/ 13 февраля 2019

Попробуйте CROSS APPLY:

SELECT 
    T1.ID, TT2.ID, T1.PointGeog.STDistance(TT2.PointGeog)
FROM #Table1 as T1
CROSS APPLY (SELECT TOP 1 T2.ID, T2.PointGeog 
  FROM #Table2 as T2
  WHERE T1.PointGeog.STDistance(T2.PointGeog) <= 100
  ORDER BY T1.PointGeog.STDistance(T2.PointGeog) ASC) as TT2
...