Tableau T_PIN
a 300 000 épingles et T_POLYGON
a 36 000 polygones. T_PIN
a cet 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
possède:
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];
Une requête pour trouver l'intersection de T_PIN
et T_POLYGON
prend plus de 45 minutes pour exécuter:
SELECT COUNT(*)
FROM T_PIN
INNER JOIN T_POLYGON
ON T_PIN.Coord.STIntersects(T_POLYGON.COORD) = 1;
Le résultat est de 4 438 318 lignes.
Comment puis-je accélérer cette requête?
Tout d'abord, vérifiez si un indice spatial est utilisé en examinant le plan d'exécution de la requête et de voir s'il existe un élément de recherche d'index en cluster (spatial).
En supposant qu'il soit utilisé, vous pouvez essayer d'ajouter un filtre secondaire/simplifié basé sur une boîte de sélection avec des polygones simplifiés pour vérifier en premier. Les matchs contre ces polygones simplifiés pourraient ensuite être exécutés à travers le filtre principal pour obtenir les résultats finaux.
1) Ajoutez une nouvelle colonne de géographie et de géométrie à la table [DBO]. [T_POLYGON] Table:
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeom geometry;
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog geography;
2) Créez les polygones de la boîte de sélection (cela implique une conversion initiale en géométrie pour profiter de STENVENVOPE ()):
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) Créer un indice spatial sur la colonne de géographie simplifiée
4) Obtenez les intersections contre cette colonne de géographie simplifiée, puis filtrez à nouveau sur les types de données de géographie correspondants. Grossièrement, quelque chose comme ça:
;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)
ÉDITER : Vous pouvez remplacer (1) et (2) avec cette colonne calculée et persistante. Crédit à Paul Blanc pour la suggestion.
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS ([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),[COORD].[STSrid]).STEnvelope().STAsBinary(),(4326))) PERSISTED
Les questions comme celle-ci prennent souvent beaucoup de temps à cause de la complexité des polygones. J'ai vu des côtes complexes (par exemple) prendre des âges pour tester des points à proximité de leurs frontières, ayant à zoomer de nombreux niveaux pour déterminer si un point est à l'intérieur ou à l'extérieur.
... Donc, vous pouvez essayer .Reduce()
'ing les polygones, pour voir si cela aide.
Et pour plus de cette fonction, regardez http://msdn.microsoft.com/en-us/library/cc627410.aspx
Selon Microsoft Docs, les index spatiaux seront utilisés avec des types de géographie sur les méthodes suivantes lorsqu'ils apparaissent au début d'un prédicat de comparaison avec une clause WHERE
:
STIntersects
STDistance
STEquals
Seuls les types de types de géométrie (liste restreinte) déclenchera l'utilisation de l'index spatial dans JOIN ... ON
, Modifiez ainsi votre code pour utiliser WHERE geog1.STIntersects(geog2) = 1
et cela devrait améliorer la vitesse.
Je recommande également de prendre des conseils Réponse de G2Server et d'ajouter ce qui suit pour filtrer et ajouter un index spatial sur celui-ci
ALTER TABLE [dbo].[T_POLYGON] ADD SimplePolysGeog AS
([geography]::STGeomFromWKB([geometry]::STGeomFromWKB([COORD].[STAsBinary](),
[COORD].[STSrid])
.STEnvelope().STAsBinary(),(4326))) PERSISTED
vous pouvez alors avoir une requête - comme Ce qui suit (j'ai écrit ce message rapidement et n'a pas encore testé, il s'agit simplement de quelque chose à essayer parce que j'ai vu que votre requête et les réponses postées les plus élevées utilisent spatial op = 1 qui n'utilisera pas un indice spatial):
SELECT
(SELECT p2.polygon_id
FROM T_Polygon p2
WHERE p2.coords.STIntersects(t.coords) = 1),
t.pin_id
FROM T_PIN t
WHERE
(SELECT t.coords.STIntersects(p.coords)
FROM T_POLYGON p
WHERE t.coords.STIntersects(p.SimplePolysGeog) = 1) = 1
FYI: ce qui précède ne fonctionne pas si SimplePolysGeog
fin de se chevaucher (comme dans une goupille peut être dans deux gènes simplifiées, il suffit de courir sur des personnes en précision dans un état et, étant donné que les polys normaux partagent la limite, les boîtes à bornes se chevauchent ), donc dans la plupart des cas d'utilisation, il lancera une erreur que la sous-requête est renvoyée à plus d'un résultat.
De MS DOCS ' Aperçu des indices spatiaux :
Méthodes de géographie supportées par des index spatiaux
Dans certaines conditions, les indices spatiaux appuient les méthodes de géographie orientées suivantes: STITRESSECTS (), Stiques () et STDISTANCE (). Pour être soutenu par un indice spatial, ces méthodes doivent être utilisées dans la clause d'une requête, et elles doivent se produire dans un prédicat de la forme générale suivante:
Geography1.Method_Name (géography2) Comparaison_OperatorValid_Number
Pour renvoyer un résultat non nul, Geography1 et Geography2 DOIT avoir le même identifiant de référence spatial (srid) . Sinon, la méthode renvoie NULL.
Les index spatiaux prennent en charge les formulaires de prédicats suivants:
Geography1.STITURSECTS (géography2) = 1!
géographie1.Stiques (géography2) = 1!
Geography1.stdistance (géography2) <numéro
Geography1.stdistance (géography2) <= numéro
Questions qui utilisent des index spatiaux
Les index spatiaux ne sont pris en charge que dans les requêtes qui incluent un opérateur spatial indexé de la clause WHERE. Par exemple, la syntaxe telle que:
[spatial object].SpatialMethod([reference spatial object]) [ = | < ] [const literal or variable]
L'optimiseur de requêtes comprend la commutativité des opérations spatiales (que
@a.STIntersects(@b) = @b.STInterestcs(@a)
). Toutefois, l'indice spatial ne sera pas utilisé si le début d'une comparaison ne contient pas l'opérateur spatial (par exempleWHERE 1 = spatial op
N'utilisera pas l'index spatial). Pour utiliser l'index spatial, réécrivez la comparaison (par exempleWHERE spatial op = 1
)....
La requête suivante fonctionnera si SimplePolysGeogs
chevauchement:
;WITH cte AS
(
SELECT T_PIN.PIN_ID,
T_POLYGON.POLYGON_ID,
T_POLYGON.COORD
FROM T_PIN
INNER JOIN T_POLYGON
ON T_PIN.COORD.STIntersects(T_POLYGON.SimplePolysGeog) = 1
)
SELECT COUNT(*)
FROM T_PIN
INNER JOIN cte
ON T_PIN_PIN_ID = cte.PIN_ID
where cte.[COORD].STIntersects(T_PIN.COORD) = 1