我需要帮助强制Oracle始终使用表“r_rapport”(〜60k行)上的索引行ID对表进行访问,以便随后避免对“r_attributfeld”(〜8m行)进行全表扫描。我已导致以下计划的查询:如何通过索引rowid在Oracle中强制访问?
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 22220 | | 63518 (2)| 00:12:43 |
|* 1 | COUNT STOPKEY | | | | | | |
| 2 | VIEW | | 2870 | 616K| | 63518 (2)| 00:12:43 |
|* 3 | SORT ORDER BY STOPKEY | | 2870 | 313K| 696K| 63518 (2)| 00:12:43 |
|* 4 | FILTER | | | | | | |
|* 5 | HASH JOIN SEMI | | 2871 | 314K| | 51920 (2)| 00:10:24 |
|* 6 | HASH JOIN RIGHT SEMI | | 2871 | 299K| | 26084 (2)| 00:05:14 |
| 7 | VIEW | VW_NSO_1 | 214 | 1070 | | 5 (20)| 00:00:01 |
|* 8 | HASH JOIN | | 214 | 5350 | | 5 (20)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | | 2 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | TEST8 | 228 | 3648 | | 2 (0)| 00:00:01 |
|* 11 | HASH JOIN SEMI | | 5848 | 582K| | 26079 (2)| 00:05:13 |
|* 12 | HASH JOIN | | 6547 | 620K| | 243 (2)| 00:00:03 |
|* 13 | INDEX RANGE SCAN | TEST5 | 47 | 470 | | 2 (0)| 00:00:01 |
| 14 | TABLE ACCESS FULL | R_RAPPORT | 60730 | 5159K| | 240 (1)| 00:00:03 |
| 15 | VIEW | VW_SQ_3 | 334K| 1633K| | 25834 (2)| 00:05:11 |
|* 16 | HASH JOIN | | 334K| 14M| 10M| 25834 (2)| 00:05:11 |
| 17 | INDEX FAST FULL SCAN | TEST4 | 476K| 4656K| | 368 (2)| 00:00:05 |
|* 18 | HASH JOIN | | 343K| 11M| 11M| 24214 (2)| 00:04:51 |
|* 19 | TABLE ACCESS FULL | R_ATTRIBUTFELD | 343K| 7722K| | 20483 (2)| 00:04:06 |
| 20 | INDEX FAST FULL SCAN| TEST3 | 1670K| 17M| | 1324 (1)| 00:00:16 |
| 21 | VIEW | VW_SQ_2 | 334K| 1633K| | 25834 (2)| 00:05:11 |
|* 22 | HASH JOIN | | 334K| 14M| 10M| 25834 (2)| 00:05:11 |
| 23 | INDEX FAST FULL SCAN | TEST4 | 476K| 4656K| | 368 (2)| 00:00:05 |
|* 24 | HASH JOIN | | 343K| 11M| 11M| 24214 (2)| 00:04:51 |
|* 25 | TABLE ACCESS FULL | R_ATTRIBUTFELD | 343K| 7722K| | 20483 (2)| 00:04:06 |
| 26 | INDEX FAST FULL SCAN | TEST3 | 1670K| 17M| | 1324 (1)| 00:00:16 |
|* 27 | INDEX RANGE SCAN | TEST6 | 1 | 8 | | 8 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------
通过添加FIRST_ROWS(1)暗示,这改变为更期望的计划:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 220 | 96 (0)| 00:00:02 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 1 | 220 | 96 (0)| 00:00:02 |
|* 3 | FILTER | | | | | |
| 4 | NESTED LOOPS | | 1 | 97 | 16 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | R_RAPPORT | 60730 | 5159K| 6 (0)| 00:00:01 |
| 6 | INDEX FULL SCAN DESCENDING | IDX_R_RAPPORT_3 | 10 | | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | TEST5 | 1 | 10 | 1 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 1 | 25 | 2 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | TEST8 | 1 | 16 | 0 (0)| 00:00:01 |
|* 11 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 12 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 13 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 15 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 17 | TABLE ACCESS BY INDEX ROWID| R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 18 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 19 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 21 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 22 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 23 | INDEX RANGE SCAN | TEST6 | 1 | 8 | 8 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
不幸的是该查询是由在运行时,如果在这里有三个子请求而不是两个,它将忽略FIRST_ROWS提示,并再次对800万行执行多个全表扫描。对于给定的数据分配,通过rowid访问总是会更快(几乎是即时),而Oracle优先选择的计划需要几秒钟的时间。
在发现那些已被弃用之前,我尝试在两个表上使用ROWID提示。
任何指针将不胜感激。
=编辑=
USE_NL &新指数
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 22220 | 3994 (1)| 00:00:48 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 102 | 22440 | 3994 (1)| 00:00:48 |
| 3 | NESTED LOOPS SEMI | | 1 | 102 | 16 (7)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 97 | 11 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | R_RAPPORT | 58985 | 5011K| 10 (0)| 00:00:01 |
|* 6 | INDEX FULL SCAN DESCENDING | TEST12 | 1 | | 9 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 13 | TABLE ACCESS BY INDEX ROWID| R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 14 | NESTED LOOPS | | 2 | 88 | 35 (0)| 00:00:01 |
| 15 | NESTED LOOPS | | 10 | 210 | 7 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 17 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | TEST6 | 1 | 8 | 8 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | TEST5 | 1 | 10 | 1 (0)| 00:00:01 |
|* 21 | VIEW | VW_NSO_1 | 105 | 525 | 5 (20)| 00:00:01 |
|* 22 | HASH JOIN | | 214 | 5350 | 5 (20)| 00:00:01 |
|* 23 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | 2 (0)| 00:00:01 |
|* 24 | INDEX RANGE SCAN | TEST8 | 228 | 3648 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------
SQL:
select /*+ FIRST_ROWS */ * from (
select *
from r_rapport a
where rb_id in (
select obj_id from obj_recht where obj_typ = 20 and obj_pid = 10065 and maske_id in (
select distinct maske_id
from obj_rechtmaske
where subj_pid = 10065
))
and rb_id in (
select id from rb_buch where pid = 10065
)
and exists (
select /*+ USE_NL(c d) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in (20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127)
and lower(d.wert) like lower('%ä%')
)
and exists (
select /*+ USE_NL(c d) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in (20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127)
and lower(d.wert) like lower('%ö%')
)
and exists (
select /*+ USE_NL(c d) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in (20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127)
and lower(d.wert) like lower('%ä%')
)
and exists (
select /*+ USE_NL(c d) */ 1
from r_teilanlage b, r_attribut c, r_attributfeld d
where a.id = b.r_id
and b.id = c.r_teilanlage_id
and c.id = d.r_attribut_id
and d.attributfeld_typ not in (20, 25, 40, 78, 79, 90, 92, 123, 124, 125, 126, 127)
and lower(d.wert) like lower('%ö%')
)
and a.id not in (
select r_id from r_gelesen where ma_id = 144
)
order by a.open_stamp desc
) where rownum <= 101;
和计划:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 220 | 1195K (1)| 03:59:08 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 1 | 220 | 1195K (1)| 03:59:08 |
|* 3 | FILTER | | | | | |
| 4 | NESTED LOOPS SEMI | | 3213 | 320K| 1018K (1)| 03:23:47 |
| 5 | NESTED LOOPS | | 6547 | 620K| 82249 (1)| 00:16:27 |
| 6 | TABLE ACCESS BY INDEX ROWID | R_RAPPORT | 60730 | 5159K| 21493 (1)| 00:04:18 |
| 7 | INDEX FULL SCAN DESCENDING | IDX_R_RAPPORT_3 | 60730 | | 152 (1)| 00:00:02 |
|* 8 | INDEX RANGE SCAN | TEST5 | 1 | 10 | 1 (0)| 00:00:01 |
|* 9 | VIEW | VW_NSO_1 | 105 | 525 | 143 (0)| 00:00:02 |
| 10 | NESTED LOOPS | | 214 | 5350 | 143 (0)| 00:00:02 |
|* 11 | INDEX RANGE SCAN | TEST7 | 141 | 1269 | 2 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | TEST8 | 2 | 32 | 1 (0)| 00:00:01 |
|* 13 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 14 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 15 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 17 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 19 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 20 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 21 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 22 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 23 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 24 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 25 | TABLE ACCESS BY INDEX ROWID | R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 26 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 27 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 28 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 29 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 30 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 31 | TABLE ACCESS BY INDEX ROWID| R_ATTRIBUTFELD | 1 | 23 | 3 (0)| 00:00:01 |
| 32 | NESTED LOOPS | | 6 | 264 | 97 (0)| 00:00:02 |
| 33 | NESTED LOOPS | | 30 | 630 | 13 (0)| 00:00:01 |
|* 34 | INDEX RANGE SCAN | TEST4 | 9 | 90 | 3 (0)| 00:00:01 |
|* 35 | INDEX RANGE SCAN | TEST3 | 3 | 33 | 2 (0)| 00:00:01 |
|* 36 | INDEX RANGE SCAN | IDX_R_ATTRIBUTFELD_1 | 6 | | 2 (0)| 00:00:01 |
|* 37 | INDEX RANGE SCAN | TEST6 | 1 | 8 | 8 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
一个可怕的,可怕的成本EST因为这个查询立即完成。
如果你想强制使用索引,我会从'INDEX'提示开始,但退一步说,您确定无法通过修复统计信息中的任何不准确情况来解决问题会导致优化器相信较慢的计划会更有效吗?特别是如果您动态组装查询,指定单个提示可能会带来相当大的问题。 –
@JustinCave - 所有优点:您可能希望确保表格统计信息是最新的/准确的。旧数据库允许基于规则的优化“强制”。什么是Oracle版本? –
正在使用的Oracle版本是10.2。我尝试了各种索引提示,这些提示没有做任何事情:/ Afair统计数据定期更新,但我没有权利自己做;将不得不检查。 – Thaylon