patternsqlModerate
Improving the performance of STIntersects
Viewed 0 times
stintersectstheimprovingperformance
Problem
Table
A query to find the intersection of
The result is 4,438,318 rows.
How can I accelerate this query?
T_PIN has 300,000 pins and T_POLYGON has 36,000 polygons. T_PIN has this index: CREATE SPATIAL INDEX [T_PIN_COORD] ON [dbo].[T_PIN]
(
[Coord]
)USING GEOGRAPHY_GRID
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH),
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY];T_POLYGON has: CREATE SPATIAL INDEX [T_POLYGON_COORD] ON [dbo].[T_POLYGON]
(
[COORD]
)USING GEOGRAPHY_GRID
WITH (GRIDS =(LEVEL_1 = HIGH,LEVEL_2 = HIGH,LEVEL_3 = HIGH,LEVEL_4 = HIGH),
CELLS_PER_OBJECT = 128, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY];A query to find the intersection of
T_PIN and T_POLYGON takes more than 45 minutes to execute:SELECT COUNT(*)
FROM T_PIN
INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;The result is 4,438,318 rows.
How can I accelerate this query?
Solution
Firstly, check whether a spatial index is being used by looking at the query execution plan and see if there is a Clustered Index Seek (Spatial) item.
Assuming it is being used, you could try adding a secondary/simplified filter based on a bounding box with simplified polygons to check for first. Matches against these simplified polygons could then be run through the primary filter to get the final results.
1) Add a new geography and geometry column to the [dbo].[T_POLYGON] table:
2) Create the bounding box polygons (this involves an initial conversion to geometry to take advantage of STEnvelope()):
3) Create a spatial index on the simplified geography column
4) Get the intersections against this simplified geography column, then filter again on the matching geography data types. Roughly, something like this:
EDIT: you can replace (1) and (2) with this computed, persisted column. credit to Paul White for the suggestion.
Assuming it is being used, you could try adding a secondary/simplified filter based on a bounding box with simplified polygons to check for first. Matches against these simplified polygons could then be run through the primary filter to get the final results.
1) Add a new geography and geometry column to the [dbo].[T_POLYGON] table:
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;2) Create the bounding box polygons (this involves an initial conversion to geometry to take advantage of STEnvelope()):
UPDATE [dbo].[T_POLYGON] SET SimplePolysGeom = geometry::STGeomFromWKB(
COORD.STAsBinary(), COORD.STSrid).STEnvelope();
UPDATE [dbo].[T_POLYGON] SET SimplePolysGeog = geography::STGeomFromWKB(
SimplePolysGeom.STAsBinary(), SimplePolysGeom.STSrid);3) Create a spatial index on the simplified geography column
4) Get the intersections against this simplified geography column, then filter again on the matching geography data types. Roughly, something like this:
;WITH cte AS
(
SELECT pinID, polygonID FROM T_PIN INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.SimplePolysGeog ) = 1
)
SELECT COUNT(*)
FROM T_PIN
INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1
AND T_PIN.pinID IN (SELECT pinID FROM cte)
AND T_POLYGON.polygonID IN (SELECT polygonID FROM cte)EDIT: you can replace (1) and (2) with this computed, persisted column. credit to Paul White for the suggestion.
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTEDCode Snippets
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;UPDATE [dbo].[T_POLYGON] SET SimplePolysGeom = geometry::STGeomFromWKB(
COORD.STAsBinary(), COORD.STSrid).STEnvelope();
UPDATE [dbo].[T_POLYGON] SET SimplePolysGeog = geography::STGeomFromWKB(
SimplePolysGeom.STAsBinary(), SimplePolysGeom.STSrid);;WITH cte AS
(
SELECT pinID, polygonID FROM T_PIN INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.SimplePolysGeog ) = 1
)
SELECT COUNT(*)
FROM T_PIN
INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1
AND T_PIN.pinID IN (SELECT pinID FROM cte)
AND T_POLYGON.polygonID IN (SELECT polygonID FROM cte)ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTEDContext
StackExchange Database Administrators Q#54578, answer score: 10
Revisions (0)
No revisions yet.