You need to reference the query block name in your index hint, if that index is in an inline view or subquery. You can use the automatically generated query block name or create one yourself with the qb_name
hint.
Sample schema and data
create table pay_assignment_actions
(
assignment_action_id number,
some_other_column number
);
create table pay_run_results
(
assignment_action_id number,
some_other_column number
);
create index PAY_RUN_RESULTS_N50 on pay_run_results(assignment_action_id);
insert into pay_assignment_actions
select level, level from dual connect by level <= 100000;
insert into pay_run_results
select level, level from dual connect by level <= 100000;
begin
dbms_stats.gather_table_stats(user, 'pay_assignment_actions');
dbms_stats.gather_table_stats(user, 'pay_run_results');
end;
/
Default plan: no indexes, use the alias
format to find the queryblock name
explain plan for
select *
from pay_assignment_actions paa
where exists
(
select *
from pay_run_results prr
where prr.assignment_action_id = paa.assignment_action_id
--to stop the default plan from using an index
and some_other_column = 5
);
select * from table(dbms_xplan.display(format => 'alias -predicate'));
Plan hash value: 1799975253
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 139 (3)| 00:00:01 |
| 1 | HASH JOIN RIGHT SEMI| | 1 | 20 | 139 (3)| 00:00:01 |
| 2 | TABLE ACCESS FULL | PAY_RUN_RESULTS | 1 | 10 | 69 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL | PAY_ASSIGNMENT_ACTIONS | 100K| 976K| 69 (2)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$5DA710D3
2 - SEL$5DA710D3 / PRR@SEL$2
3 - SEL$5DA710D3 / PAA@SEL$1
Use auto-generated query block name to force index
explain plan for
select /*+ index(@SEL$2 prr) */ *
from pay_assignment_actions paa
where exists
(
select *
from pay_run_results prr
where prr.assignment_action_id = paa.assignment_action_id
--to stop the default plan from using an index
and some_other_column = 5
);
select * from table(dbms_xplan.display(format => '-predicate'));
Plan hash value: 1805560573
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 476 (1)| 00:00:01 |
| 1 | HASH JOIN RIGHT SEMI | | 1 | 20 | 476 (1)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| PAY_RUN_RESULTS | 1 | 10 | 406 (1)| 00:00:01 |
| 3 | INDEX FULL SCAN | PAY_RUN_RESULTS_N50 | 100K| | 201 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL | PAY_ASSIGNMENT_ACTIONS | 100K| 976K| 69 (2)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
Use QB_NAME to make your own query block name
explain plan for
select /*+ index(@my_subquery prr) */ *
from pay_assignment_actions paa
where exists
(
select /*+ qb_name(my_subquery) */ *
from pay_run_results prr
where prr.assignment_action_id = paa.assignment_action_id
--to stop the default plan from using an index
and some_other_column = 5
);
select * from table(dbms_xplan.display(format => 'alias -predicate'));
Plan hash value: 1805560573
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 476 (1)| 00:00:01 |
| 1 | HASH JOIN RIGHT SEMI | | 1 | 20 | 476 (1)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| PAY_RUN_RESULTS | 1 | 10 | 406 (1)| 00:00:01 |
| 3 | INDEX FULL SCAN | PAY_RUN_RESULTS_N50 | 100K| | 201 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL | PAY_ASSIGNMENT_ACTIONS | 100K| 976K| 69 (2)| 00:00:01 |
-------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$08BA3066
2 - SEL$08BA3066 / PRR@MY_SUBQUERY
3 - SEL$08BA3066 / PRR@MY_SUBQUERY
4 - SEL$08BA3066 / PAA@SEL$1
USE_NL when objects span query blocks
Objects in different query blocks can be referenced by their full object alias, like this:
explain plan for
select /*+ index(@SEL$2 prr) use_nl(prr@sel$2 paa@sel$1) */ *
from pay_assignment_actions paa
where exists
(
select *
from pay_run_results prr
where prr.assignment_action_id = paa.assignment_action_id
--to stop the default plan from using an index
and some_other_column = 5
);
select * from table(dbms_xplan.display(format => '-predicate'));
Plan hash value: 2326545440
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 476 (1)| 00:00:06 |
| 1 | NESTED LOOPS | | 1 | 20 | 476 (1)| 00:00:06 |
| 2 | SORT UNIQUE | | 1 | 10 | 406 (1)| 00:00:05 |
| 3 | TABLE ACCESS BY INDEX ROWID| PAY_RUN_RESULTS | 1 | 10 | 406 (1)| 00:00:05 |
| 4 | INDEX FULL SCAN | PAY_RUN_RESULTS_N50 | 100K| | 201 (1)| 00:00:03 |
| 5 | TABLE ACCESS FULL | PAY_ASSIGNMENT_ACTIONS | 1 | 10 | 69 (2)| 00:00:01 |
--------------------------------------------------------------------------------------------------------