Como forçar o Oracle Spatial para selecionar um plano de execução “executável”
-
20-08-2019 - |
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')
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.