A questão:
Eu tenho uma tabela espacial (road lines), armazenada usando o SDE.ST_GEOMETRY
tipo de dados definido pelo usuário da ESRI em um geodatabase Oracle 12c . Quero listar os vértices da linha para que eu possa acessar e atualizar suas coordenadas. Se eu estivesse usando SDO_GEOMETRY / Oracle Locator, usaria a
SDO_UTIL.GETVERTICES
função Mas não estou usando SDO_GEOMETRY / Oracle Locator e não há função equivalente no SDE.ST_GEOMETRY
. As únicas SDE.ST_GEOMETRY
funções que posso encontrar que pertencem aos vértices são ST_PointN
e ST_NumPoints
.
Eu vim com uma consulta que faz tudo isso com êxito - obtém os vértices da linha como linhas (inspiradas nesta 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""))"
Ele CROSS JOINS
alinha as linhas ROADS
de uma NUMBERS
tabela (e limita os resultados ao número de vértices em cada linha).
Estatísticas: (atualizado)
- Cada linha tem no máximo 30 vértices (média de 4,38 vértices por linha)
- ROADS possui 3.997 linhas
- NUMBERS possui 30 linhas (números sequenciais iniciando em 1)
- O conjunto de resultados possui 17.536 linhas
No entanto, o desempenho é ruim (40 segundos) e não consigo deixar de pensar - existe uma maneira mais elegante de fazer isso? Para mim, usar uma tabela de números e uma junção cruzada parece uma abordagem desleixada. Existe uma maneira melhor?
Os termos do leigo seriam apreciados; Eu sou um cara de obras públicas, não um DBA.
Atualização # 1:
Se eu remover as linhas 3 e 4 (sequência de funções relacionadas a X e Y) da consulta, ela será executada instantaneamente. Mas é claro, não posso simplesmente remover essas linhas, preciso das colunas X e Y. Portanto, isso me leva a acreditar que o desempenho lento tem algo a ver com as funções X e Y.
No entanto, se eu exportar os pontos para uma tabela estática e executar as funções X e Y nela, isso também será executado instantaneamente.
Então, isso significa que o desempenho lento é causado pelas funções X e Y, exceto, bem, não, não é? Estou confuso.
Atualização # 2:
Se eu retirar os X e Y da consulta, colocá-los em uma consulta externa e adicionar ROWNUM à consulta interna, será muito mais rápido (16 segundos - atualizado):
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 que o ROWNUM ajuda o desempenho aqui: Por que adicionar o ROWNUM a uma consulta melhora o desempenho?
Embora essa melhoria de desempenho seja boa, ainda não é suficiente. E não posso deixar de pensar que ainda não entendo completamente como a consulta funciona ou por que é tão lenta quanto é.
A questão ainda permanece: existe uma maneira melhor?