Somewhat counter-intuitively you can drop them but need to be careful on what comes *after* that..Here's an example - I'll create a big table with an index
SQL> create table t as
2 select d.* from dba_objects d,
3 ( select 1 from dual connect by level <= 100 );
Table created.
SQL> create index ix on t ( object_id );
Index created.
SQL> set autotrace traceonly explain
SQL> select /*+ index_rs_asc(t ix) */ max(owner)
2 from t
3 where object_id > 0 ;
Execution Plan
----------------------------------------------------------
Plan hash value: 2143077847
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 8268K (1)| 00:05:23 |
| 1 | SORT AGGREGATE | | 1 | 11 | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| T | 8247K| 86M| 8268K (1)| 00:05:23 |
|* 3 | INDEX RANGE SCAN | IX | 8247K| | 18296 (1)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("OBJECT_ID">0)
I added the hint to make his query run really slow - I'm going to use the index to scan every row in the table. So now I'll start it running with a trace enabled
SQL> set autotrace off
SQL> exec dbms_monitor.session_trace_enable(waits=>true);
PL/SQL procedure successfully completed.
SQL> select /*+ index_rs_asc(t ix) */ max(owner)
2 from t
3 where object_id > 0 ;
[running]
and in another session I dropped the index. And.....nothing broke.
If I look at the trace file I see:
WAIT #1344857178368: nam='db file sequential read' ela= 203 file#=12 block#=20527 blocks=1 obj#=136229 tim=1349784362738
WAIT #1344857178368: nam='db file sequential read' ela= 187 file#=12 block#=20648 blocks=1 obj#=136229 tim=1349784363300
WAIT #1344857178368: nam='db file sequential read' ela= 191 file#=12 block#=20649 blocks=1 obj#=136229 tim=1349784363846
WAIT #1344857178368: nam='db file sequential read' ela= 178 file#=12 block#=20650 blocks=1 obj#=136229 tim=1349784364373
WAIT #1344857178368: nam='db file sequential read' ela= 172 file#=12 block#=20651 blocks=1 obj#=136229 tim=1349784364898
WAIT #1344857178368: nam='db file sequential read' ela= 188 file#=12 block#=20652 blocks=1 obj#=136229 tim=1349784365442
WAIT #1344857178368: nam='db file sequential read' ela= 197 file#=12 block#=20653 blocks=1 obj#=136229 tim=1349784366001
...
...
This means we *kept* using the index even though it was dropped. The index entries were still there on disk.
Now if I had (for example) created a new table that re-used this space, I'd get an error from the query. Here's a couple of videos showing that in a different but related scenario
Back to your question - a safer and easy way to handle this is do it two phases
1) make the index invisible (alter index IX invisible)
Wait for (say) a day to see if any queries goes terribly wrong - if they do, simply make it visible again or change the query. Once you're happy then at a later date do
2) drop index