2011-01-27 9 views
5

quiero calcular la distancia entre gps-point para obtener la distancia completa entre el primero y el último punto.T-SQL Fastforward Cursor vs. foreach

Mi pregunta es: ¿Qué es más rápido?

  • Para cargar todas las filas en un DataTable y calcular en C# .NET a través de foreach o
  • Caluclate que en SQL-Server utilizando un StoredProcedure con un FastForward Cursor.

Hablo de alrededor de 400,000 filas.

+1

Lo más rápido sería calcular ** en el servidor **, pero ** sin un cursor ** ..... –

+0

@marc_s: ¿Hay alguna manera de agregar una distancia para cada fila sin un cursor? – mabstrei

+0

Vea mi respuesta: no nos está dando muchos detalles, por lo que solo puedo brindarle una idea muy generalizada ... –

Respuesta

4

Definitivamente intentaré hacer esto en el servidor; intente evitar arrastrar hacia abajo 400,000 filas solo para calcular un solo número (al final).

También: Intentaré hacerlo sin un cursor, si es posible. Los cursores son una pesadilla en SQL Server; deben evitarse a toda costa.

En su caso, sin conocer la estructura detallada de su tabla, definitivamente podría hacerlo, p. un CTE recursivo (Expresión común de tabla) que comienza con el primer elemento y una distancia total de 0.0, y luego resume recursivamente todos los puntos restantes, calculando la distancia entre el punto (x + 1) y el punto x, y sumando al total anterior.

Al final, debe tener un CTE que muestre todos los puntos de paso, todas las distancias entre dos puntos intermedios y la distancia total de todo el recorrido.

Eso CTE sería algo así como:

;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 
+0

¿Dónde está la ORDEN POR o extraño algo? –

+0

@Jonas Elfström: no se necesita ORDER BY - hay una fila que es el ancla, y luego desde allí, siempre es una conexión 'SomeRow.PrevWaypointID = previousRow.WaypointID' - el orden se define por la relación entre un waypoint y es el anterior. –

+0

Ah, se perdió la construcción de la lista vinculada. –

3

Si está utilizando SQL Server 2008 Recomiendo probar para almacenarlos como el tipo geography y luego

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

pero para saber realmente lo que es más rápido que tenga que probar ambos.

+1

Typo? La segunda línea debe ser 'declare @ point2 ...'? – MusiGenesis

+0

Sí, es un buen error tipográfico antiguo. –

2

Mi entendimiento es que incluso utilizando un cursor en SQL, todavía es órdenes de magnitud más rápido que la iteración en el código del lado frontal. En ese momento, ADO y DAO eran las tecnologías en cuestión, por lo que las cosas pueden haber cambiado un poco con el advenimiento de ADO.NET y DataSets.

Sin embargo, apuesto a que T-SQL, que está diseñado específicamente para este tipo de cosas, es aún más eficiente.

La excepción podría ser si necesita aplicar una lógica especial durante su iteración, pero considero que un Cursor SQL correctamente configurado, realizando su cálculo en la parte posterior, superará al Dataset.

Lo mejor de todo sería hacerlo sin el cursor en SQL, si es posible. . .

+0

Estaba publicando mientras otros daban mejores respuestas. . . – XIVSolutions

2

Si está utilizando Sql Server 2008 (o posterior), puede hacer todo lo posible en el servidor utilizando el tipo de geografía. He aquí una muestra para calcular la distancia entre dos puntos:

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

No estoy seguro de si esto puede ser usado sin un cursor, pero tal vez.

Si está utilizando una versión anterior de SQL Server, igual podría escribir la fórmula de distancia usted mismo como un proceso almacenado, y también hacer todo lo relacionado con el servidor.

Descargar todo el conjunto a un cliente y hacer todos los cálculos del lado del cliente casi con seguridad tomará mucho más tiempo, ya que el tiempo de descarga será mucho mayor que el tiempo de cálculo.