T-SQL Fastforward Cursor против foreach - PullRequest
5 голосов
/ 27 января 2011

Я хочу рассчитать расстояние между GPS-точкой, чтобы получить полное расстояние между первой и последней точкой.

Мой вопрос: что быстрее?

  • Загрузитьвсе строки в DataTable и вычислить его в c # .net с помощью foreach или
  • . Вычислить его на Sql-сервере с помощью StoredProcedure с курсором FastForward.

Я говорю о количествеоколо 400 000 строк.

Ответы [ 4 ]

4 голосов
/ 27 января 2011

Я бы определенно попытался сделать это на сервере - старайтесь не перетаскивать 400 000 строк, чтобы просто вычислить одно число (в конце).

Также: я бы попробовал сделать это без курсора , если это возможно. Курсоры являются кошмаром на SQL Server - их следует избегать любой ценой.

В вашем случае - не зная вашей детальной структуры таблицы - вы можете определенно сделать, например, рекурсивное CTE (Common Table Expression), которое начинается с первого элемента и общего расстояния 0,0, а затем рекурсивно суммирует все другие промежуточные точки, вычисляя расстояние между точкой (x + 1) и точкой x и суммируя предыдущий итог.

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

Этот CTE будет выглядеть примерно так:

;WITH Waypoints AS
(
    -- anchor your query
    SELECT
       WaypointID, PrevWaypointID, Long, Lat, 0.0 as Distance, 0.0 as SumOfDistance
    FROM
       dbo.Waypoint
    WHERE
       PrevWaypointID IS NULL  --  or some other condition

    UNION  -- recurse

    SELECT
       WaypointID, Long, Lat, 
       dbo.GetDistanceBetween(wp.WaypointID, pts.WaypointID),   -- distance
       pts.SumOfDistance + dbo.GetDistanceBetween(wp.WaypointID, pts.WaypointID)  -- sum
    FROM
       dbo.Waypoint wp
    INNER JOIN
       Waypoints pts ON wp.PrevWaypointID = pts.WaypointID          
    WHERE
       (some condition; ID = 1 or PreviousWaypointID IS NULL or something)
)
SELECT * FROM Waypoints
3 голосов
/ 27 января 2011

Если вы используете SQL Server 2008, я бы рекомендовал попытаться сохранить их как тип geography, а затем

declare @point1 geography = 'POINT (-42 84)';
declare @point2 geography = 'POINT (-3 10)';
select @point1.STDistance (@point2)

, но чтобы действительно знать, что быстрее, вы должны попробовать оба.

2 голосов
/ 27 января 2011

Если вы используете Sql Server 2008 (или новее), то вы можете делать все на сервере, используя тип географии. Вот пример для расчета расстояния между двумя точками:

SELECT geography::Point(lat1, lon1, 4326).STDistance(geography::Point(lat2, lon2, 4326))

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

Если вы используете более старую версию SQL Server, вы все равно можете написать формулу расстояния в виде хранимого процесса и делать все на стороне сервера.

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

2 голосов
/ 27 января 2011

Насколько я понимаю, даже при использовании курсора в SQL он все равно на несколько порядков быстрее, чем итерации в коде на стороне.В то время ADO и DAO были технологиями, о которых идет речь, поэтому, возможно, ситуация немного изменилась с появлением ADO.NET и DataSets.

Однако я держу пари, что T-SQL, разработанный специально для этого типа вещей, все еще более эффективен.

Исключением может быть, если вам потребуется применить специальную логику во время итерации, но я предполагаю, что правильно настроенный SQL-курсор, выполняющий вычисления на обратной стороне, превзойдет набор данных.1006 * Лучше всего было бы делать это без курсора в SQL, если вы можете.,.

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