У меня есть таблица, в которой я храню координаты широты / долготы, и я хочу сделать запрос, в котором я хочу получить все записи, которые находятся на расстоянии до определенной точки.
В этой таблице около 10 миллионов записей, и есть индекс над полями Lat / Long
Это не должно быть точным. Помимо прочего, я рассматриваю этот 1 градус в длину == 1 градус в латах, что, как я знаю, неверно, но получаемый мною эллипс достаточно хорош для этой цели.
Для моих примеров ниже, скажем, речь идет о [40, 140], а мой радиус в градусах составляет 2 градуса.
Я пробовал это двумя способами:
1) Я создал UDF для вычисления квадрата расстояния между двумя точками, и я запускаю этот UDF в запросе.
SELECT Lat, Long FROM Table
WHERE (Lat BETWEEN 38 AND 42)
AND (Long BETWEEN 138 AND 142)
AND dbo.SquareDistance(Lat, Long, 40, 140) < 4
Сначала я фильтрую по квадрату, чтобы ускорить запрос и позволить SQL использовать индекс, а затем уточняю его, чтобы сопоставить только записи, которые попадают в круг, с моим UDF.
2) Запустите запрос, чтобы получить квадрат (такой же, как прежде, но без последней строки), введите ВСЕ эти записи в мой код ASP.Net и вычислите круг на стороне ASP.Net (та же идея, рассчитайте квадрат расстояния, чтобы сохранить вызов Sqrt и сравнить с квадратом моего радиуса).
К моему удивлению, вычисление круга на стороне .Net примерно в 10 раз быстрее, чем с использованием UDF, что заставляет меня поверить, что я делаю что-то ужасно неправильно с этим UDF ...
Это код, который я использую:
CREATE FUNCTION [dbo].[SquareDistance]
(@Lat1 float, @Long1 float, @Lat2 float, @Long2 float)
RETURNS float
AS
BEGIN
-- Declare the return variable here
DECLARE @Result float
DECLARE @LatDiff float, @LongDiff float
SELECT @LatDiff = @Lat1 - @Lat2
SELECT @LongDiff = @Long1 - @Long2
SELECT @Result = (@LatDiff * @LatDiff) + (@LongDiff * @LongDiff)
-- Return the result of the function
RETURN @Result
END
Я что-то здесь упускаю?
Разве использование UDF в SQL Server не должно быть намного быстрее, чем передача примерно на 25% больше записей, чем необходимо .Net, с накладными расходами DataReader, связью между процессами и чем-то еще?
Есть ли что-то, что я делаю ужасно неправильно в той UDF, которая заставляет его работать медленно?
Есть ли способ улучшить его?
Большое спасибо!