Wie zu zwingen, Oracle Spatial einen „ausführbar“ Ausführungsplan auszuwählen
-
20-08-2019 - |
Frage
A (räumliche) Abfrage in Oracle 10g erhält verschiedenen Ausführungsplan nur in Abhängigkeit von einem Parameterwert. Und leider kann Oracle nicht zu einer der Pläne auszuführen, einen Fehler gibt. Ändern Wert (unter 282-284) oder Operator (= auf <) gibt ein Ergebnis. Warum sind die Pläne anders? Warum Oracle wählt einen nicht ausführbaren Plan? Was zu tun, Oracle zu zwingen, einen ausführbaren Ausführungsplan zu wählen?
Die Abfrage:
select nn.poi_id as id
from
poi p,
(select pl.poi_id
from
poi_loc pl,
poi_loc pl2
where
pl2.poi_id = 769
and
pl.poi_id<>769
and
sdo_nn(pl.wgs84, pl2.wgs84)='TRUE'
) nn
where
cat_id = 282
and
p.id = nn.poi_id
and
rownum<7;
Geben Fehler:
ORA-13249: SDO_NN cannot be evaluated without using index
ORA-06512: at "MDSYS.MD", line 1723
ORA-06512: at "MDSYS.MDERR", line 17
ORA-06512: at "MDSYS.PRVT_IDX", line 22
Planen, die nicht ausgeführt:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 315 | 6 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID | POI_LOC | 1 | 153 | 2 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 1 | 315 | 6 (0)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 162 | 4 (0)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID| POI | 1 | 9 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | POI_CAT_ID_IDX | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| POI_LOC | 1 | 153 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | POI_LOC_POI_ID_IDX | 1 | | 1 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | POI_LOC_POI_ID_IDX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
1 - filter(ROWNUM<7)
2 - filter("MDSYS"."SDO_NN"("PL"."WGS84","PL2"."WGS84")='TRUE')
5 - filter("P"."ID"<>769)
6 - access("CAT_ID"=282)
8 - access("P"."ID"="PL"."POI_ID")
filter("PL"."POI_ID"<>769)
9 - access("PL2"."POI_ID"=769)
Planen, die ausführt und gibt Ergebnis
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 1890 | 106 (1)| 00:00:02 |
|* 1 | COUNT STOPKEY | | | | | |
|* 2 | HASH JOIN | | 6 | 1890 | 106 (1)| 00:00:02 |
|* 3 | TABLE ACCESS BY INDEX ROWID | POI | 573 | 5157 | 41 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | POI_CAT_ID_IDX | 573 | | 2 (0)| 00:00:01 |
| 5 | NESTED LOOPS | | 301 | 92106 | 65 (2)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID| POI_LOC | 1 | 153 | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | POI_LOC_POI_ID_IDX | 1 | | 1 (0)| 00:00:01 |
|* 8 | TABLE ACCESS BY INDEX ROWID| POI_LOC | 302 | 46206 | 65 (2)| 00:00:01 |
|* 9 | DOMAIN INDEX | POI_LOC_SP_IDX | | | | |
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<7)
2 - access("P"."ID"="PL"."POI_ID")
3 - filter("P"."ID"<>769)
4 - access("CAT_ID"=284)
7 - access("PL2"."POI_ID"=769)
8 - filter("PL"."POI_ID"<>769)
9 - access("MDSYS"."SDO_NN"("PL"."WGS84","PL2"."WGS84")='TRUE')
Lösung
Sie müssen nur den Hinweis, die richtige Art und Weise schreiben:
select nn.poi_id as id
from
poi p,
(select /*+ index (pl POI_LOC_SP_IDX) */ pl.poi_id
from
poi_loc pl,
poi_loc pl2
where
pl2.poi_id = 769
and
pl.poi_id<>769
and
sdo_nn(pl.wgs84, pl2.wgs84)='TRUE'
) nn
where
cat_id = 282
and
p.id = nn.poi_id
and rownum<7;
Der Grund für den Fehler ist, dass das Optimierungsprogramm nicht den räumlichen Index verwenden wählt, weil er denkt, dass andere (nicht-räumliche) indizierten Prädikate selektiver sind. Um zu klären: Sie müssen einen räumlichen Index für räumliche Abfragen zu arbeiten, aber der Optimierer kann wählen, es nicht zu benutzen. Dies funktioniert gut für SDO_RELATE und SDO_ANYINTERACT Betreiber, aber nicht für SDO_NN.
Andere Tipps
In jedem Fall sollten Sie den Index für wgs84 hinzuzufügen.
Wenn Sie keine Ahnung, was das alles bedeutet, das DBA fragen.
finden Sie unter http: // download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_index_query.htm#i1000846 für ein paar Informationen.