Die Frage:
Ich habe eine räumliche Tabelle (Straßenlinien), die unter Verwendung des SDE.ST_GEOMETRY
benutzerdefinierten ESRI -Datentyps in einer Oracle 12c- Geodatabase gespeichert ist . Ich möchte die Linienscheitelpunkte auflisten, damit ich letztendlich auf ihre Koordinaten zugreifen und diese aktualisieren kann. Wenn ich SDO_GEOMETRY / Oracle Locator verwenden würde, würde ich die
SDO_UTIL.GETVERTICES
Funktion verwenden. Ich verwende jedoch nicht SDO_GEOMETRY / Oracle Locator und es gibt keine entsprechende Funktion in SDE.ST_GEOMETRY
. Die einzigen SDE.ST_GEOMETRY
Funktionen, die ich finden kann, die sich auf Eckpunkte beziehen, sind ST_PointN
und ST_NumPoints
.
Ich habe eine Abfrage erstellt, die all dies erfolgreich ausführt - die Linienscheitelpunkte werden als Zeilen abgerufen (inspiriert von dieser Seite ):
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 werden CROSS JOINS
die Linien in der ROADS
Tabelle zu einer NUMBERS
Tabelle (und die Ergebnisse werden auf die Anzahl der Eckpunkte in jeder Linie begrenzt).
Statistik: (aktualisiert)
- Jede Linie hat maximal 30 Eckpunkte (durchschnittlich 4,38 Eckpunkte pro Linie)
- ROADS hat 3.997 Linien
- NUMBERS hat 30 Zeilen (fortlaufende Nummern ab 1)
- Die Ergebnismenge enthält 17.536 Zeilen
Die Leistung ist jedoch schlecht (40 Sekunden), und ich kann nicht anders als zu denken - gibt es einen eleganteren Weg, dies zu tun? Die Verwendung einer Zahlentabelle und eines Cross-Joins scheint mir ein schlampiger Ansatz zu sein. Gibt es einen besseren Weg?
Laienbedingungen würden geschätzt; Ich bin ein Typ für öffentliche Arbeiten, kein DBA.
Update Nr. 1:
Wenn ich die Zeilen 3 und 4 (Zeichenfolge von X & Y-bezogenen Funktionen) aus der Abfrage entferne, wird sie sofort ausgeführt. Aber natürlich kann ich diese Zeilen nicht einfach entfernen, ich brauche die X & Y-Spalten. Das lässt mich glauben, dass die langsame Leistung etwas mit den X & Y-Funktionen zu tun hat.
Wenn ich die Punkte jedoch in eine statische Tabelle exportiere und dann die X & Y-Funktionen darauf ausführe, wird dies ebenfalls sofort ausgeführt.
Bedeutet dies also, dass die langsame Leistung durch die X & Y-Funktionen verursacht wird, außer, nein, ist dies nicht der Fall? Ich bin verwirrt.
Update Nr. 2:
Wenn ich das X und Y aus der Abfrage herausbringe, sie in eine äußere Abfrage einfüge und der inneren Abfrage ROWNUM hinzufüge, geht es viel schneller (16 Sekunden - aktualisiert):
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 erklärt hier, warum ROWNUM die Leistung verbessert : Warum verbessert das Hinzufügen von ROWNUM zu einer Abfrage die Leistung?
Diese Leistungsverbesserung ist zwar gut, aber noch nicht gut genug. Und ich kann nicht anders, als zu glauben, dass ich immer noch nicht ganz verstehe, wie die Abfrage funktioniert oder warum sie so langsam ist wie sie ist.
Die Frage bleibt noch: Gibt es einen besseren Weg?