La question:
J'ai une table spatiale (lignes de route), stockée à l'aide du SDE.ST_GEOMETRY
type de données défini par l' utilisateur d'ESRI dans une géodatabase Oracle 12c . Je veux lister les sommets des lignes afin que je puisse finalement accéder et mettre à jour leurs coordonnées. Si j'utilisais SDO_GEOMETRY / Oracle Locator, j'utiliserais la
SDO_UTIL.GETVERTICES
fonction. Mais je n'utilise pas SDO_GEOMETRY / Oracle Locator, et il n'y a pas de fonction équivalente dans SDE.ST_GEOMETRY
. Les seules SDE.ST_GEOMETRY
fonctions que je peux trouver concernant les sommets sont ST_PointN
et ST_NumPoints
.
J'ai trouvé une requête qui réussit à faire tout cela - obtient les sommets des lignes sous forme de lignes (inspiré par cette page ):
1 SELECT a.ROAD_ID
2 ,b.NUMBERS VERTEX_INDEX
3 ,a.SDE.ST_X(SDE.ST_PointN(a.SHAPE, b.NUMBERS)) AS X
4 ,a.SDE.ST_Y(SDE.ST_PointN(a.SHAPE, b.NUMBERS)) AS Y
5 FROM ENG.ROADS a
6 CROSS JOIN ENG.NUMBERS b
7 WHERE b.NUMBERS <= SDE.ST_NumPoints(a.SHAPE)
8 --removed to do explain plan: ORDER BY ROAD_ID, b.NUMBERS
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5996 | 1545K| | 262 (1)| 00:00:01 |
| 1 | MERGE JOIN | | 5996 | 1545K| | 262 (1)| 00:00:01 |
| 2 | INDEX FULL SCAN | R23715_SDE_ROWID_UK | 30 | 90 | | 1 (0)| 00:00:01 |
|* 3 | SORT JOIN | | 3997 | 1018K| 2392K| 261 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL| ROAD | 3997 | 1018K| | 34 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
" 3 - access(""B"".""NUMBERS""<=""SDE"".""ST_NumPoints""(""A"".""SHAPE""))"
" filter(""B"".""NUMBERS""<=""SDE"".""ST_NumPoints""(""A"".""SHAPE""))"
Il CROSS JOINS
les lignes du ROADS
tableau à un NUMBERS
tableau (et limite les résultats au nombre de sommets dans chaque ligne).
Statistiques: (mis à jour)
- Chaque ligne a un maximum de 30 sommets (moyenne de 4,38 sommets par ligne)
- ROADS compte 3 997 lignes
- NUMBERS a 30 lignes (numéros séquentiels commençant à 1)
- L'ensemble de résultats contient 17 536 lignes
Cependant, les performances sont médiocres (40 secondes), et je ne peux m'empêcher de penser - existe-t-il une façon plus élégante de le faire? Pour moi, l'utilisation d'une table de nombres et d'une jointure croisée semble être une approche bâclée. Y a-t-il une meilleure façon?
Les termes de Layman seraient appréciés; Je suis un gars des travaux publics, pas un DBA.
Mise à jour # 1:
Si je supprime les lignes 3 et 4 (chaîne de fonctions liées à X et Y) de la requête, elle s'exécute instantanément. Mais bien sûr, je ne peux pas simplement supprimer ces lignes, j'ai besoin des colonnes X & Y. Cela m'amène donc à croire que la lenteur des performances a quelque chose à voir avec les fonctions X & Y.
Cependant, si j'exporte les points dans une table statique, puis que j'exécute les fonctions X et Y dessus, cela s'exécute également instantanément.
Donc, cela signifie-t-il que la lenteur des performances est causée par les fonctions X et Y, sauf que non, ce n'est pas le cas? Je suis confus.
Mise à jour # 2:
Si j'apporte les X et Y de la requête, les place dans une requête externe et ajoute ROWNUM à la requête interne, alors c'est beaucoup plus rapide (16 secondes - mis à jour):
SELECT
ROWNUM
,ROAD_ID
,VERTEX_INDEX
,SDE.ST_X(ST_POINT) AS X
,SDE.ST_Y(ST_POINT) AS Y
FROM
(
SELECT
ROWNUM
,a.ROAD_ID
,b.NUMBERS VERTEX_INDEX
,SDE.ST_PointN(a.SHAPE, b.NUMBERS) AS ST_POINT
FROM ENG.ROAD a
CROSS JOIN ENG.NUMBERS b
WHERE b.NUMBERS <= SDE.ST_NumPoints(a.SHAPE)
)
--removed to do explain plan: ORDER BY ROAD_ID, VERTEX_INDEX
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5996 | 322K| | 262 (1)| 00:00:01 |
| 1 | COUNT | | | | | | |
| 2 | VIEW | | 5996 | 322K| | 262 (1)| 00:00:01 |
| 3 | COUNT | | | | | | |
| 4 | MERGE JOIN | | 5996 | 1545K| | 262 (1)| 00:00:01 |
| 5 | INDEX FULL SCAN | R23715_SDE_ROWID_UK | 30 | 90 | | 1 (0)| 00:00:01 |
|* 6 | SORT JOIN | | 3997 | 1018K| 2392K| 261 (1)| 00:00:01 |
| 7 | TABLE ACCESS FULL| ROAD | 3997 | 1018K| | 34 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
" 6 - access(""B"".""NUMBERS""<=""SDE"".""ST_NumPoints""(""A"".""SHAPE""))"
" filter(""B"".""NUMBERS""<=""SDE"".""ST_NumPoints""(""A"".""SHAPE""))"
Justin Cave explique pourquoi ROWNUM améliore les performances ici: Pourquoi l'ajout de ROWNUM à une requête améliore-t-il les performances?
Bien que cette amélioration des performances soit bonne, elle n'est pas encore suffisante. Et je ne peux pas m'empêcher de penser que je ne comprends toujours pas complètement comment fonctionne la requête ou pourquoi elle est aussi lente qu'elle l'est.
La question se pose toujours: existe-t-il une meilleure solution?