I have geography field of irregular shapes. Geography field can vary from hundred to thousands of Lat/Long points that define that shape. In regards to size it could be from several US. Postal Codes to a size of entire US State. In order to have increased performance I have build Spacial index on that field. On frequent basis I have to find vehicles based on Lat/Long point that are within specific zone.
My original approach was this.
WITH LastP
AS ( SELECT vlp.ID
,GEOGRAPHY::STPointFromText('POINT(' + CAST(vlp.Long AS VARCHAR(20)) + ' '
+ CAST(vlp.Lat AS VARCHAR(20)) + ')', 4326) AS LastKnownPoint
FROM LastPosition AS vlp )
SELECT lp.ID
,zn.ZONE
FROM dbo.GeogZone AS zn WITH ( NOLOCK )
JOIN @zones AS z
ON zn.Zone = z.Zone
JOIN LastP AS lp
ON lp.LastKnownPoint.STWithin(zn.ZoneGeog) = 1
I was getting all records from my table LastPosition
and than I converted Lat/Long into Geography
point and later JOIN
using STWithin
function. This process works great but can be very slow. I have tried to adjust Spacial indexes but it did not make big changed.
To increase performance I want to introduce the following process.
From Geography type I will extract NorthLat, SouthLat, EastLong, WestLong
Now I can limit the number of results before I do compare in the following matter.
WITH LastP
AS ( SELECT vlp.ID
,GEOGRAPHY::STPointFromText('POINT(' + CAST(vlp.Long AS VARCHAR(20)) + ' '
+ CAST(vlp.Lat AS VARCHAR(20)) + ')', 4326) AS LastKnownPoint
FROM LastPosition AS vlp
WHERE (vlp.Long BETWEEN @WestLong and @EastLong) AND (vlp.Lat BETWEEN @SouthLat AND @NorthLat))
SELECT lp.ID
,zn.ZONE
FROM dbo.GeogZone AS zn
JOIN @zones AS z
ON zn.Zone = z.Zone
JOIN LastP AS lp
ON lp.LastKnownPoint.STWithin(zn.ZoneGeog) = 1
Here is the code for building the box.
DECLARE @geomenvelope GEOMETRY;
DECLARE @BoundingBox AS TABLE
(
SouthLat DECIMAL(10, 8)
,NorthLat DECIMAL(10, 8)
,EastLong DECIMAL(10, 8)
,WestLong DECIMAL(10, 8)
);
SELECT @geomenvelope = GEOMETRY::STGeomFromWKB(zn.ZoneGeog.STAsBinary(), zn.ZoneGeog.STSrid).STEnvelope()
FROM dbo.GeogZone AS zn
WHERE zn.Zone = 'CA-1'
INSERT INTO @BoundingBox (SouthLat,NorthLat,EastLong,WestLong)
SELECT @geomenvelope.STPointN(1).STY
,@geomenvelope.STPointN(3).STY
,@geomenvelope.STPointN(1).STX
,@geomenvelope.STPointN(3).STX
SELECT *
FROM @BoundingBox
My question: Is there an alternative (easier) way to get East, West, North, South Points from my Geography Field?