Pergunta

A (espacial) consulta no Oracle 10g recebe plano de execução diferente dependendo apenas um valor de parâmetro. E, infelizmente, a Oracle não pode executar um dos planos em tudo, dando um erro. Alterando o valor (abaixo 282-284) ou operador (= a <) dá um resultado. Por que os planos de diferente? Por que seleciona oracle um plano inexeqüível? O que fazer para forçar a Oracle para selecionar um plano de execução executável?

A consulta:

  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;

Dando erro:

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

Plano que não executar:

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

Plano que executa e dá resultado

| 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')
Foi útil?

Solução

Você só precisa escrever a dica a maneira correta:

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;

A razão para o erro é que as escolhe otimizador não usar o índice espacial porque pensa que outros (não-espaciais) predicados indexados são mais seletivos. Para esclarecer: você deve ter um índice espacial para consultas espaciais para trabalhar, mas o otimizador pode optar por não usá-lo. Esta multa trabalha para operadores SDO_RELATE e SDO_ANYINTERACT, mas não para SDO_NN.

Outras dicas

Em qualquer caso, você deve adicionar o índice para WGS84.

Se você não tem nenhum indício que tudo isso significa, peça ao DBA.

http: // download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_index_query.htm#i1000846 para algumas informações.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top