Как заставить Oracle Spatial выбрать “исполняемый” план выполнения

StackOverflow https://stackoverflow.com/questions/1044157

Вопрос

(Пространственный) запрос в Oracle 10g получает разный план выполнения, зависящий только от значения параметра.И, к сожалению, Oracle вообще не может выполнить один из планов, выдавая ошибку.Изменение значения (ниже 282 на 284) или оператора (= на <) дает результат.Почему планы отличаются?Почему oracle выбирает неисполнимый план?Что сделать, чтобы заставить Oracle выбрать исполняемый план выполнения?

Запрос:

  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;

Выдает ошибку:

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

План, который не выполняется:

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

План, который выполняется и дает результат

| 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')
Это было полезно?

Решение

Вам просто нужно правильно написать подсказку:

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;

Причина ошибки заключается в том, что оптимизатор предпочитает не использовать пространственный индекс, поскольку считает, что другие (непространственные) индексированные предикаты более избирательны.Чтобы прояснить:для работы пространственных запросов у вас должен быть пространственный индекс, но оптимизатор может отказаться от его использования.Это отлично работает для операторов SDO_RELATE и SDO_ANYINTERACT, но не для SDO_NN.

Другие советы

В любом случае, вы должны добавить индекс для wgs84.

Если вы понятия не имеете, что все это значит, спросите администратора базы данных.

видишь http://download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_index_query.htm#i1000846 для получения некоторой информации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top