La pregunta:
Tengo una tabla espacial (líneas de ruta), almacenada usando el SDE.ST_GEOMETRY
tipo de datos definido por el usuario de ESRI en una geodatabase Oracle 12c . Quiero enumerar los vértices de las líneas para poder acceder y actualizar sus coordenadas. Si estuviera usando SDO_GEOMETRY / Oracle Locator, entonces usaría la
SDO_UTIL.GETVERTICES
función. Pero no estoy usando SDO_GEOMETRY / Oracle Locator, y no hay una función equivalente en SDE.ST_GEOMETRY
. Las únicas SDE.ST_GEOMETRY
funciones que puedo encontrar que pertenecen a los vértices son ST_PointN
y ST_NumPoints
.
Se me ocurrió una consulta que hace todo esto con éxito: obtiene los vértices de la línea como filas (inspirados en esta página ):
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""))"
Es CROSS JOINS
las líneas en la ROADS
tabla a una NUMBERS
tabla (y limita los resultados al número de vértices en cada línea).
Estadísticas: (actualizado)
- Cada línea tiene un máximo de 30 vértices (promedio de 4.38 vértices por línea)
- CARRETERAS tiene 3,997 líneas
- NÚMEROS tiene 30 filas (números secuenciales que comienzan en 1)
- El conjunto de resultados tiene 17.536 filas.
Sin embargo, el rendimiento es pobre (40 segundos), y no puedo evitar pensar: ¿hay una manera más elegante de hacer esto? Para mí, usar una tabla de números y una unión cruzada parece un enfoque descuidado. ¿Hay una mejor manera?
Los términos del laico serían apreciados; Soy un tipo de Obras Públicas, no un DBA.
Actualización n. ° 1:
Si elimino las líneas 3 y 4 (cadena de funciones relacionadas con X e Y) de la consulta, se ejecuta instantáneamente. Pero, por supuesto, no puedo simplemente eliminar estas líneas, necesito las columnas X e Y. Entonces esto me lleva a creer que el rendimiento lento tiene algo que ver con las funciones X e Y.
Sin embargo, si exporto los puntos a una tabla estática y luego ejecuto las funciones X e Y, también se ejecuta instantáneamente.
Entonces, ¿esto significa que el rendimiento lento es causado por las funciones X e Y, excepto, bueno, no, no lo es? Estoy confundido.
Actualización n. ° 2:
Si saco las X e Y de la consulta, las pongo en una consulta externa y agrego ROWNUM a la consulta interna, entonces es mucho más rápido (16 segundos - actualizado):
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 explica por qué ROWNUM ayuda al rendimiento aquí: ¿por qué agregar ROWNUM a una consulta mejora el rendimiento?
Si bien esta mejora del rendimiento es buena, aún no es lo suficientemente buena. Y no puedo evitar pensar que todavía no entiendo completamente cómo funciona la consulta o por qué es tan lenta como es.
La pregunta sigue en pie: ¿hay una mejor manera?