2011-01-27 11 views
5

Voglio caluire la distanza tra il punto gps per ottenere la distanza completa tra il primo e l'ultimo punto.T-SQL Fastforward Cursor vs. foreach

La mia domanda è: cosa è più veloce?

  • Per caricare tutte le righe in un DataTable e calcolare in C# .NET tramite foreach o
  • Caluclate su Sql-Server utilizzando uno StoredProcedure con FastForward cursore.

Parlo di un lotto di circa 400.000 file.

+1

Il più veloce sarebbe quello di calcolarlo ** sul server **, ma ** senza un cursore ** ..... –

+0

@marc_s: C'è un modo per aggiungere una distanza per ogni riga senza un cursore? – mabstrei

+0

Vedere la mia risposta: non ci fornisci molti dettagli, quindi posso solo fornire un'idea molto generalizzata ... –

risposta

4

Proverei sicuramente a farlo sul server: prova a evitare di trascinare verso il basso 400.000 righe solo per calcolare un singolo numero (alla fine).

Inoltre: proverei a farlo senza un cursore, se possibile. I cursori sono un incubo su SQL Server - dovrebbero essere evitati a tutti i costi.

Nel tuo caso, non conoscendo la tua struttura dettagliata della tabella, potresti sicuramente fare ad es. un CTE ricorsivo (Common Table Expression) che inizia con il primo elemento e una distanza totale di 0.0, e quindi ricorsivamente riassume tutti gli altri punti modo, calcolando la distanza tra il punto (x + 1) e il punto x, e sommando fino al totale precedente.

Alla fine, si dovrebbe avere un CTE che mostra tutti i punti di tragitto, tutte le distanze tra due waypoint e la distanza totale dell'intero viaggio.

Questo CTE sarebbe qualcosa di simile:

;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

Dov'è l'ORDINE DI o mi manca qualcosa? –

+0

@Jonas Elfström: no ORDER BY necessario - c'è una * riga * che è l'ancora, e da quel momento in poi, è sempre una connessione 'SomeRow.PrevWaypointID = previousRow.WaypointID' - l'ordine è definito dalla relazione tra un waypoint e è precedente. –

+0

Ah, ho perso la costruzione della lista collegata. –

3

Se si utilizza SQL Server 2008 Suggerirei cercando di memorizzarli come il tipo geography e poi

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

ma per sapere esattamente cosa è più veloce che devi provare entrambi.

+1

Typo? La seconda riga dovrebbe essere 'declare @ point2 ...'? – MusiGenesis

+0

Sì, un buon vecchio errore è stato. –

2

La mia comprensione è che anche utilizzando un cursore in SQL, è ancora ordini di grandezza più veloce di iterazione nel codice front-side. Al momento, ADO e DAO erano le tecnologie in questione, quindi le cose potrebbero essere cambiate un po 'con l'avvento di ADO.NET e DataSet.

Tuttavia, scommetto che T-SQL, essendo progettato specificamente per questo tipo di cose, è ancora più efficiente.

L'eccezione potrebbe essere se è necessario applicare una logica speciale durante l'iterazione, ma è necessario che un Cursore SQL configurato correttamente, eseguendo il calcolo sul lato posteriore, superi il set di dati.

La cosa migliore sarebbe di farlo senza il cursore in SQL, se possibile. . .

+0

Stavo postando mentre altri davano risposte migliori. . . – XIVSolutions

2

Se si utilizza Sql Server 2008 (o più recente), è possibile eseguire qualsiasi operazione sul server utilizzando il tipo di geografia. Ecco un esempio di calcolo della distanza tra due punti:

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

Non sono sicuro se questo può essere utilizzato senza un cursore, ma forse.

Se si utilizza una versione precedente di SQL Server, è possibile scrivere la formula della distanza come un processo memorizzato e fare anche tutto il lato server.

Scaricare l'intero set su un client e fare tutti i calcoli sul lato client richiederà quasi certamente molto più tempo, poiché il tempo di download sarà molto maggiore del tempo di calcolo.