There isn't a hint to force anti-hash joins. But the optimizer can rewrite a not in to get the same plan as a outer join:
create table a (id not null, junk not null) as
select rownum, 'filler' from dual
connect by level <= 10000;
create table b (id not null, junk not null) as
select * from a where rownum <= 9100;
create index ai on a(id);
create index bi on b(id);
set serveroutput off
select /*+ gather_plan_statistics */* from a
where a.id not in (select b.id from b);
select * from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
PLAN_TABLE_OUTPUT
SQL_ID fmxrz93gm1ypz, child number 1
-------------------------------------
select /*+ gather_plan_statistics */* from a where a.id not in
(select b.id from b)
Plan hash value: 3901740010
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 900 |00:00:00.05 | 66 | 19 |
|* 1 | HASH JOIN RIGHT ANTI | | 1 | 10000 | 900 |00:00:00.05 | 66 | 19 |
| 2 | INDEX FAST FULL SCAN| BI | 1 | 9100 | 9100 |00:00:00.01 | 24 | 19 |
| 3 | TABLE ACCESS FULL | A | 1 | 10000 | 10000 |00:00:00.02 | 42 | 0 |
-------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."ID"="B"."ID")
select /*+ gather_plan_statistics */a.*
from a , b
where a.id = B.id (+)
and B.id IS NULL;
select * from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST'));
PLAN_TABLE_OUTPUT
SQL_ID asb6jak5unbjs, child number 0
-------------------------------------
select /*+ gather_plan_statistics */a.* from a , b where a.id =
B.id (+) and B.id IS NULL
Plan hash value: 3901740010
----------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 900 |00:00:00.07 | 66 |
|* 1 | HASH JOIN RIGHT ANTI | | 1 | 10000 | 900 |00:00:00.07 | 66 |
| 2 | INDEX FAST FULL SCAN| BI | 1 | 9100 | 9100 |00:00:00.01 | 24 |
| 3 | TABLE ACCESS FULL | A | 1 | 10000 | 10000 |00:00:00.02 | 42 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."ID"="B"."ID")
So:
What exactly are your queries?
Which version are you on?
What's the DDL for the tables and indexes?
What are the plans for the two queries?
You can read more about possible strategies for hinting these from Jonathan Lewis at:
https://jonathanlewis.wordpress.com/2015/04/13/not-exists/