如何强制 Oracle Spatial 选择“可执行”文件 执行计划

发布于 2024-07-25 16:03:05 字数 4147 浏览 8 评论 0原文

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

A (spatial) query in Oracle 10g gets different execution plan depending only on a parameter value. And sadly Oracle cannot execute one of the plans at all, giving an error. Changing value (below 282 to 284) or operator (= to <) gives a result. Why are the plans different? Why oracle selects an unexecutable plan? What to do to force Oracle to select an executable execution plan?

The query:

  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 error:

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 which doesn't execute:

| 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 which executes and gives result

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

森林迷了鹿 2024-08-01 16:03:05

您只需要以正确的方式编写提示即可:

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。

You just need to write the hint the proper way:

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;

The reason for the error is that the optimizer chooses not to use the spatial index because it thinks that other (non-spatial) indexed predicates are more selective. To clarify: you MUST have a spatial index for spatial queries to work, but the optimizer may choose not to use it. This works fine for SDO_RELATE and SDO_ANYINTERACT operators, but not for SDO_NN.

随心而道 2024-08-01 16:03:05

无论如何,您应该添加 wgs84 的索引。

如果您不知道这一切意味着什么,请询问 DBA。

请参阅 http://download-west .oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_index_query.htm#i1000846 了解一些信息。

In any case, you should add the index for wgs84.

If you have no clue what all this means, ask the DBA.

see http://download-west.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_index_query.htm#i1000846 for some info.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文