Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
timgaunt
Posting Yak Master
115 Posts |
Posted - 2012-05-17 : 04:23:02
|
I'm porting some C# code over to SQL and need to calculate the cardinal direction (North, East, South, West etc) from two sets of co-ordinates (currently stored as floats).I've pretty much ported the code directly and I was wondering whether this the best way to be doing it -from both the perspective of the function and the code itself.The return int represents an enum identifier from the code.This will be used to update about 1m records at a time so although not crucial (it's a background task), performance is important. CREATE FUNCTION CalculateCardinalDirection( @fromLatitude FLOAT, @fromLongitude FLOAT, @toLatitude FLOAT, @toLongitude FLOAT)RETURNS intASBEGIN DECLARE @dLon float, @dPhi float, @bearing float, @pi180 FLOAT, @piDoubled FLOAT, @piPlus2 FLOAT, @direction int SET @pi180 = pi() / 180 SET @piDoubled = 2 * pi() SET @piPlus2 = pi() / 4 SET @dLon = ((@toLongitude - @fromLongitude) * @pi180) SET @dPhi = log(tan((@toLatitude * @pi180) / 2 + @piPlus2) / tan((@fromLatitude * @pi180) / 2 + @piPlus2)) IF (abs(@dLon) > pi()) BEGIN IF @dLon > 0 BEGIN SET @dLon = -(@piDoubled - @dLon) END ELSE BEGIN SET @dLon = (@piDoubled + @dLon) END END SET @bearing = cast(((ATN2(@dLon, @dPhi) * 180 / pi()) + 360) AS DECIMAL(18,15)) % cast(360 AS DECIMAL(18,15)) RETURN CASE --NE WHEN @bearing >= 22.5 AND @bearing < 67.5 THEN 2 --E WHEN @bearing >= 67.5 AND @bearing < 112.5 THEN 4 --SE WHEN @bearing >= 112.5 AND @bearing < 157.5 THEN 6 --S WHEN @bearing >= 157.5 AND @bearing < 202.5 THEN 8 --SW WHEN @bearing >= 202.5 AND @bearing < 247.5 THEN 10 --W WHEN @bearing >= 247.5 AND @bearing < 292.5 THEN 12 --NW WHEN @bearing >= 292.5 AND @bearing < 337.5 THEN 14 --N ELSE 0 ENDENDGO ----------------------------http://blogs.thesitedoctor.co.uk/tim/ |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2012-05-17 : 09:24:29
|
Tim1. why are you porting it over from c# to sql2. Have you benchmarked this and does it scale better than c#3. Have you looked at using CLR<><><><><><><><><><><><><><><><><>If you don't have the passion to help people, you have no passion |
 |
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2012-05-17 : 10:20:30
|
1. Because it's being executed across so many records one at a time rather than bulk (there's no way to work around this in the application) and it takes over an hour to run2. Benchmarked no but running across the same record set it takes a matter of seconds3. Not in this instance no, that's a good shout if you think it will be faster----------------------------I've finally started blogging (all be it badly!)Check it out:http://blogs.thesitedoctor.co.uk/tim/ |
 |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2012-05-17 : 12:33:55
|
Timfunctions are also called for each row. for 1 million rows , 1 million calls to your function. your porting the function to sql will not accomplish anything different than the c# code. you might want to do an inline calculation instead of using a function for such large dataset. if someone else could chime in to confirm or object what I am saying.<><><><><><><><><><><><><><><><><>If you don't have the passion to help people, you have no passion |
 |
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2012-05-17 : 12:47:23
|
I don't want to get too technical but in the instance of this codebase the data access layer will effectively move the entire dataset it's about to work on into memory and try and work on that. We've tried chunking etc. The speed issue is not caused by the method which works out the location, it's a data retrieval/update issue. We're currently working on resolving that side of things but my interest is more about the performance of the above SQL code and whether I'm missing a trick :)----------------------------I've finally started blogging (all be it badly!)Check it out:http://blogs.thesitedoctor.co.uk/tim/ |
 |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2012-05-18 : 14:29:01
|
TimIf you could provide a large set of data for long+lat, I think we could provide a more accurate answer. As is the code looks good to me. I am testing it out with a very small subset of data and it is not bringing the result I am expecting.can you provide long lat points that hasIF (abs(@dLon) > pi())<><><><><><><><><><><><><><><><><>If you don't have the passion to help people, you have no passion |
 |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2012-05-18 : 15:00:29
|
this is what I was thinking to use as inline calculation. you leverage a well indexed tabledrop table dbo.bearingscreate table dbo.bearings(bearingstart decimal(10,1), bearingend decimal(10,1), bearingid int, CONSTRAINT [PK_bearings] PRIMARY KEY CLUSTERED ( bearingid asc, bearingstart ASC, bearingend ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]insert into dbo.bearingsselect 22.5, 67.4, 2UNIONselect 67.5, 112.4, 4UNIONselect 112.5, 157.4, 6UNIONselect 157.5, 202.4, 8UNIONselect 202.5, 247.4, 10UNIONselect 247.5, 292.4, 10UNIONselect 292.5, 337.4, 14select * from bearings--Addis Abeba 09°02'N 38°42'E--Bahir Dar 11°37'N 37°10'Edeclare @fromLatitude FLOAT, @fromLongitude FLOAT, @toLatitude FLOAT, @toLongitude FLOATSET @fromLatitude = 9.022736SET @fromLongitude = 38.746799SET @toLatitude = 11.616667SET @toLongitude = 38.066667 DROP TABLE dbo.Citiescreate table dbo.Cities(FromCityName varchar(50), FromLatitude float, FromLongitude float, ToCityName varchar(50),ToLatitude float, ToLongitude float) ON [PRIMARY]insert into CitiesSELECT 'Addis Abeba', @fromLatitude, @fromLongitude, 'Bahir Dar', @toLatitude , @toLongitudeselect * from CitiesDECLARE @dLon float, @dPhi float, @bearing float, @pi180 FLOAT, @piDoubled FLOAT, @piPlus2 FLOAT, @direction int SET @pi180 = pi() / 180 SET @piDoubled = 2 * pi() SET @piPlus2 = pi() / 4PRINT @pi180PRINT @piDoubledPRINT @piPlus2SELECT [FromCityName] ,[FromLatitude] ,[FromLongitude] ,[ToCityName] ,[ToLatitude] ,[ToLongitude] , ABS( (( ToLongitude- FromLongitude) * @pi180) ) dLon, log(tan((ToLongitude * @pi180) / 2 + @piPlus2) / tan((FromLongitude * @pi180) / 2 + @piPlus2)) dPhi, CASE WHEN (( ToLongitude- FromLongitude) * @pi180) > 0 THEN -( @piDoubled - ((ToLongitude - FromLongitude) * @pi180) ) ELSE ( @piDoubled + ((ToLongitude - FromLongitude) * @pi180) ) END dLonCalculated FROM dbo.Cities ;with cteCities([FromCityName] ,[FromLatitude] ,[FromLongitude] ,[ToCityName] ,[ToLatitude] ,[ToLongitude] ,dLon ,dPhi ,dLonCalculated ,bearing )AS(SELECT [FromCityName] ,[FromLatitude] ,[FromLongitude] ,[ToCityName] ,[ToLatitude] ,[ToLongitude] , ABS( (( ToLongitude- FromLongitude) * @pi180) ) dLon, log(tan((ToLongitude * @pi180) / 2 + @piPlus2) / tan((FromLongitude * @pi180) / 2 + @piPlus2)) dPhi, CASE WHEN (( ToLongitude- FromLongitude) * @pi180) > 0 THEN -( @piDoubled - ((ToLongitude - FromLongitude) * @pi180) ) ELSE ( @piDoubled + ((ToLongitude - FromLongitude) * @pi180) ) END dLonCalculated, CASE WHEN (( ToLongitude- FromLongitude) * @pi180) > 0 THEN cast(((ATN2(-( @piDoubled - ((ToLongitude - FromLongitude) * @pi180) ), (log(tan((ToLongitude * @pi180) / 2 + @piPlus2) / tan((FromLongitude * @pi180) / 2 + @piPlus2))) ) * 180 / pi()) + 360) AS DECIMAL(18,15)) % cast(360 AS DECIMAL(18,15)) ELSE cast(((ATN2(( @piDoubled + ((ToLongitude - FromLongitude) * @pi180) ), (log(tan((ToLongitude * @pi180) / 2 + @piPlus2) / tan((FromLongitude * @pi180) / 2 + @piPlus2))) ) * 180 / pi()) + 360) AS DECIMAL(18,15)) % cast(360 AS DECIMAL(18,15)) END bearing FROM dbo.Cities)SELECT * FROM cteCities cte cross apply dbo.bearings brwhere bearing between br.bearingstart and bearingend Something seems wrong with the result. The resulting bearing says Bahir Dar is E of Addis Abeba when actually it is the opposite.<><><><><><><><><><><><><><><><><>If you don't have the passion to help people, you have no passion |
 |
|
timgaunt
Posting Yak Master
115 Posts |
Posted - 2012-05-18 : 20:13:48
|
Interesting. Thanks----------------------------I've finally started blogging (all be it badly!)Check it out:http://blogs.thesitedoctor.co.uk/tim/ |
 |
|
|
|
|
|
|