2009-06-25 3 views
1

Eine (räumliche) Abfrage in Oracle 10g erhält einen anderen Ausführungsplan, der nur von einem Parameterwert abhängt. Und leider kann Oracle einen der Pläne überhaupt nicht ausführen und gibt einen Fehler. Ändern von Wert (unter 282 bis 284) oder Operator (= <) ergibt ein Ergebnis. Warum unterscheiden sich die Pläne? Warum wählt Orakel einen nicht ausführbaren Plan? Was zu tun, um Oracle zu zwingen, einen ausführbaren Ausführungsplan auszuwählen?Erzwingen, dass Oracle Spatial einen ausführbaren Ausführungsplan auswählt

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; 

Giving 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 

-Plan, 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) 

Plan, 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') 

Antwort

0

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 der Optimierer den räumlichen Index nicht verwenden wählt, weil denkt, dass andere (nicht-räumliche) Prädikate indiziert sind selektiver. Um zu verdeutlichen: Sie MÜSSEN einen räumlichen Index für räumliche Abfragen haben, um zu funktionieren, aber der Optimierer kann entscheiden, ihn nicht zu verwenden. Dies funktioniert für die Operatoren SDO_RELATE und SDO_ANYINTERACT, aber nicht für SDO_NN.

0

In jedem Fall sollten Sie den Index für wgs84 hinzufügen.

Wenn Sie keine Ahnung haben, was das alles bedeutet, fragen Sie den DBA.

siehe http://download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_index_query.htm#i1000846 für einige Informationen.

+0

Der Index ist schon da. Wie kann ich Orakel dazu zwingen, es jedes Mal zu benutzen? – Riivo

+0

Wenn Sie den Index bereits haben, ist Ihr Plan möglicherweise veraltet. Wenn dies in pl/sql ist, kompilieren Sie es neu. Ansonsten aktualisiere die Statistiken mit dem Paket dbms_stats. Wenn Sie alle diese Dinge getan haben, funktioniert es immer noch nicht, verwenden Sie Optimizer Hinweise: SELECT/* + INDEX (YOU_INDEX_NAME) */nn.poi_id als id blar blar blar blar –

+0

Ich glaube nicht, dass der Plan veraltet ist . Seine Ebene sql. Abhängig von einem Wert wählt oracle manchmal einen Plan, der POI_LOC_SP_IDX verwendet, und die Abfrage funktioniert einwandfrei. Der Hinweis, den Sie gaben, hilft auch in diesem Fall nicht. – Riivo

Verwandte Themen