Invisible index
11g的Invisible index和前面版本的virtual index是完全不同的。
Invisible index是有segment的,并且在做DML操作的时候是维护这个索引的,而virtual index并没有真实的被创建出来,没有分配segment空间,只是optimizer可见而已。
让我来说的话,virtual index是在QA环境上做测试的一个工具,用处不大,主要被oracle自己使用(Oracle Enterprise Manger Tuning Pack),
而invisible index是在production实施的一个过渡阶段,对于某些大型的复杂的application很有价值。
另外invisible index对于drop index也很有帮助,可以做为drop index的一个过渡阶段。
在drop前(建议先monitoring usage)先设置index invisible,观测一段时间,比如一个星期,如果有问题可以很快的rollback,如果没有问题再drop index。
在我06年初的那篇文章里提到virtual index的几个特性:
1. 需要设定隐藏参数 “_use_nosegment_indexes”=true, 因为涉及隐藏参数,所以不建议在prod环境使用,除非oracle建议
2. hint 对virtual index有效
3. 没有hint的情况下,RBO时虚拟索引对于optimizer不可见, CBO时oracle会考虑使用虚拟索引
这里对应的也列出Invisible的几个特点:
1. 可以在创建的时候指定,也可以用alter index xx invisible 修改,是oracle support的new feature.
- SQL> create index test_idx on test(object_id) invisible;
- Index created.
- SQL> select index_name,visibility from user_indexes where index_name='TEST_IDX';
- INDEX_NAME VISIBILITY
- ------------------------------------------------------------------------------------------ ---------------------------
- TEST_IDX INVISIBLE
- SQL> alter index test_idx visible;
- Index altered.
- SQL> select index_name,visibility from user_indexes where index_name='TEST_IDX';
- INDEX_NAME VISIBILITY
- ------------------------------------------------------------------------------------------ ---------------------------
- TEST_IDX VISIBLE
- SQL> alter index test_idx invisible;
- Index altered.
- SQL> select index_name,visibility from user_indexes where index_name='TEST_IDX';
- INDEX_NAME VISIBILITY
- ------------------------------------------------------------------------------------------ ---------------------------
- TEST_IDX INVISIBLE
2. Invisible index对于optimizer是不可见的,除非session开始设置OPTIMIZER_USE_INVISIBLE_INDEXES=true。文档上说加hint也可以使用invisible index,不过我没有试出来,
可能是一个bug,也可能oracle在发布正式版的时候去掉了这一功能
- SQL> alter index test_idx invisible;
- Index altered.
- SQL> select index_name,visibility from user_indexes where index_name='TEST_IDX';
- INDEX_NAME VISIBILITY
- ------------------------------------------------------------------------------------------ ---------------------------
- TEST_IDX INVISIBLE
- SQL> set autot on
- SQL> select object_id from test where object_id=100;
- OBJECT_ID
- ----------
- 100
- 100
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 1357081020
- --------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- --------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 2 | 8 | 86 (2)| 00:00:02 |
- |* 1 | TABLE ACCESS FULL| TEST | 2 | 8 | 86 (2)| 00:00:02 |
- --------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter("OBJECT_ID"=100)
- Statistics
- ----------------------------------------------------------
- 1 recursive calls
- 0 db block gets
- 332 consistent gets
- 324 physical reads
- 0 redo size
- 455 bytes sent via SQL*Net to client
- 419 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 2 rows processed
- SQL> alter session set OPTIMIZER_USE_INVISIBLE_INDEXES=true;
- Session altered.
- SQL> select object_id from test where object_id=100;
- OBJECT_ID
- ----------
- 100
- 100
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 2882402178
- -----------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- -----------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 2 | 8 | 1 (0)| 00:00:01 |
- |* 1 | INDEX RANGE SCAN| TEST_IDX | 2 | 8 | 1 (0)| 00:00:01 |
- -----------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - access("OBJECT_ID"=100)
- Statistics
- ----------------------------------------------------------
- 1 recursive calls
- 0 db block gets
- 3 consistent gets
- 1 physical reads
- 0 redo size
- 455 bytes sent via SQL*Net to client
- 419 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 2 rows processed
- SQL> alter session set OPTIMIZER_USE_INVISIBLE_INDEXES=false;
- Session altered.
- SQL> select /*+ index(TEST TEST_IDX) */ object_id from test where object_id=100;
- OBJECT_ID
- ----------
- 100
- 100
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 1357081020
- --------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
- --------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 2 | 8 | 86 (2)| 00:00:02 |
- |* 1 | TABLE ACCESS FULL| TEST | 2 | 8 | 86 (2)| 00:00:02 |
- --------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter("OBJECT_ID"=100)
- Statistics
- ----------------------------------------------------------
- 1 recursive calls
- 0 db block gets
- 332 consistent gets
- 324 physical reads
- 0 redo size
- 455 bytes sent via SQL*Net to client
- 419 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 2 rows processed
3. invisible index在RBO下同样不可见
- SQL> alter session set optimizer_mode=rule;
- Session altered.
- SQL> select object_id from test where object_id=100;
- OBJECT_ID
- ----------
- 100
- 100
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 1357081020
- ----------------------------------
- | Id | Operation | Name |
- ----------------------------------
- | 0 | SELECT STATEMENT | |
- |* 1 | TABLE ACCESS FULL| TEST |
- ----------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter("OBJECT_ID"=100)
- Note
- -----
- - rule based optimizer used (consider using cbo)
- Statistics
- ----------------------------------------------------------
- 0 recursive calls
- 0 db block gets
- 333 consistent gets
- 4 physical reads
- 0 redo size
- 455 bytes sent via SQL*Net to client
- 419 bytes received via SQL*Net from client
- 2 SQL*Net roundtrips to/from client
- 0 sorts (memory)
- 0 sorts (disk)
- 2 rows processed
4. 如果索引上是invisible,dbms_stat收集统计信息时要指定OPTIMIZER_USE_INVISIBLE_INDEXES=true,analyze没有问题,这看上去也像一个bug
- SQL> alter session set OPTIMIZER_USE_INVISIBLE_INDEXES=false;
- Session altered.
- SQL> exec dbms_stats.gather_table_stats(user,'TEST');
- BEGIN dbms_stats.gather_table_stats(user,'TEST'); END;
- *
- ERROR at line 1:
- ORA-00904: : invalid identifier
- ORA-06512: at "SYS.DBMS_STATS", line 17806
- ORA-06512: at "SYS.DBMS_STATS", line 17827
- ORA-06512: at line 1
- SQL> alter session set OPTIMIZER_USE_INVISIBLE_INDEXES=true;
- Session altered.
- SQL> exec dbms_stats.gather_table_stats(user,'TEST');
- PL/SQL procedure successfully completed.
总体来说invisible index是一个很实用的新特性,不过上面小小的几个测试已经暴露了两个疑似bug的问题。
所以对于invisible index我个人意见还是谨慎为好,最好等11g出R2的时候再在production上尝试。