如何强制 Oracle Spatial 选择“可执行”文件 执行计划
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您只需要以正确的方式编写提示即可:
错误的原因是优化器选择不使用空间索引,因为它认为其他(非空间)索引谓词更具选择性。 澄清一下:您必须有一个空间索引才能使空间查询工作,但优化器可能选择不使用它。 这适用于 SDO_RELATE 和 SDO_ANYINTERACT 运算符,但不适用于 SDO_NN。
You just need to write the hint the proper way:
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.
无论如何,您应该添加 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.