La domanda:
Ho una tabella spaziale (linee stradali), memorizzata usando il SDE.ST_GEOMETRY
tipo di dati definito dall'utente di ESRI in un geodatabase Oracle 12c . Voglio elencare i vertici di linea in modo da poter infine accedere e aggiornare le loro coordinate. Se stessi usando SDO_GEOMETRY / Oracle Locator, allora userei la
SDO_UTIL.GETVERTICES
funzione. Ma non sto usando SDO_GEOMETRY / Oracle Locator e non esiste una funzione equivalente in SDE.ST_GEOMETRY
. Le uniche SDE.ST_GEOMETRY
funzioni che posso trovare che riguardano i vertici sono ST_PointN
e ST_NumPoints
.
Ho elaborato una query che esegue correttamente tutto ciò: ottiene i vertici di riga come righe (ispirati a questa pagina ):
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""))"
È CROSS JOINS
le linee nella ROADS
tabella a una NUMBERS
tabella (e limita i risultati al numero di vertici in ogni riga).
Statistiche: (aggiornato)
- Ogni riga ha un massimo di 30 vertici (media di 4,38 vertici per riga)
- ROADS ha 3.997 linee
- NUMBERS ha 30 righe (numeri sequenziali che iniziano da 1)
- Il set di risultati ha 17.536 righe
Tuttavia, le prestazioni sono scadenti (40 secondi) e non posso fare a meno di pensare: esiste un modo più elegante per farlo? Per me, usare una tabella dei numeri e un cross join sembra un approccio sciatto. Esiste un modo migliore?
I termini di Layman sarebbero apprezzati; Sono un ragazzo di lavori pubblici, non un DBA.
Aggiornamento n. 1:
Se rimuovo le righe 3 e 4 (stringa di funzioni correlate a X e Y) dalla query, viene eseguito immediatamente. Ma ovviamente non posso semplicemente rimuovere queste righe, ho bisogno delle colonne X e Y. Quindi questo mi porta a credere che le prestazioni lente abbiano qualcosa a che fare con le funzioni X e Y.
Tuttavia, se esporto i punti in una tabella statica e quindi eseguo le funzioni X e Y su di essa, anche questo viene eseguito all'istante.
Quindi, questo significa che le prestazioni lente sono causate dalle funzioni X e Y, tranne, beh, no? Non ho capito bene.
Aggiornamento n. 2:
Se tiro fuori X e Y dalla query, li inserisco in una query esterna e aggiungo ROWNUM alla query interna, allora è molto più veloce (16 secondi - aggiornato):
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 spiega perché ROWNUM aiuta le prestazioni qui: Perché l'aggiunta di ROWNUM a una query migliora le prestazioni?
Mentre questo miglioramento delle prestazioni è buono, non è ancora abbastanza buono. E non posso fare a meno di pensare che non riesco ancora a capire come funziona la query o perché è così lenta.
La domanda è ancora valida: esiste un modo migliore?