ORACLE虚拟索引(Virtual Index)

ORACLE虚拟索引(Virtual Index)

 

虚拟索引概念

虚拟索引(Virtual Indexes)是一个定义在数据字典中的假索引(fake index),它没有相关的索引段。虚拟索引的目的是模拟索引的存在而不用真实的创建一个完整索引。这允许开发者创建虚拟索引来查看相关执行计划而不用等到真实创建完索引才能查看索引对执行计划的影响,并且不会增加存储空间的使用。如果我们观察到优化器生成了一个昂贵的执行计划并且SQL调整指导建议我们对某些的某列创建索引,但在生产数据库环境中创建索引与测试并不总是可以操作。我们需要确保创建的索引将不会对数据库中的其它查询产生负面影响,因此可以使用虚拟索引。

A virtual index is a "fake" index whose definition exists in the data dictionary, but has no associated index segment. The purpose of virtual indexes is to simulate the existence of an index - without actually building a full index. This allows developers to run an explain plan as if the index is present without waiting for the index creation to complete and without using additional disk space. If we observe that optimizer is creating a plan which is expensive and SQL tuning advisor suggest us to create an index on a column, in case of production database it may not be always feasible to create an index and test the changes. We need to make sure that the created index will not have any negative impact on the execution plan of other queries running in the database.So here is why a virtual index comes into picture.

虚拟索引应用

虚拟索引是Oracle 9.2.0.1以后开始引入的,虚拟索引的应用场景主要是在SQL优化调优当中,尤其是在生产环境的优化、调整。这个确实是一个开创性的功能,试想,如果一个SQL性能很差,但是涉及几个数据量非常大的表,你尝试新增一个索引,但是你也不确定优化器一定就能使用该索引或者使用该索引后,执行计划就能朝着预想的那样发展,但是在大表上创建索引、删除索引也是一个代价非常高的动作,有可能引起一些性能问题或者影响其他SQL的执行计划,而且创建一个实际的索引需要较长的时间,而虚拟索引几乎非常快速,在性能优化和调整中经常被使用。其实说白了,虚拟索引主要是给DBA做SQL优化使用,根据它的测试效果来判断是否需要创建实际索引。

 

虚拟索引测试

 

创建一个测试表,我们在这个测试表上做一些实验。

SQL> set linesize 1200
SQL> select version from v$instance;

 

VERSION

-----------------

11.2.0.1.0

 

SQL> create table test          

  2  as

  3  select * from dba_objects;

 

Table created.

SQL> set autotrace traceonly explain;

SQL> select * from test where object_id=60;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |    11 |  2277 |   282   (1)| 00:00:04 |

|*  1 |  TABLE ACCESS FULL| TEST |    11 |  2277 |   282   (1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("OBJECT_ID"=60)

 

Note

-----

   - dynamic sampling used for this statement (level=2)

创建虚拟索引,检查执行计划是否走索引扫描。实际上创建虚拟索引就是普通索引语法后面加一个NOSEGMENT关键字即可,B*TREE INDEX和BITMAP INDEX都可以。

SQL> set autotrace off;
SQL> 

SQL> create index idx_test_virtual on test(object_id) nosegment;

 

Index created.

 

SQL> set autotrace traceonly explain;

SQL> select * from test where object_id=60;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |    11 |  2277 |   282   (1)| 00:00:04 |

|*  1 |  TABLE ACCESS FULL| TEST |    11 |  2277 |   282   (1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("OBJECT_ID"=60)

 

Note

-----

   - dynamic sampling used for this statement (level=2)

如上所示,并没有使用虚拟索引。如果要使用所创建的虚拟索引,必须设置隐含参数"_USE_NOSEGMENT_INDEXES"=TRUE(默认为FALSE)后CBO优化器模式才能使用虚拟索引,RBO优化器模式无法使用虚拟索引

SQL> alter session set "_USE_NOSEGMENT_INDEXES"=true;
 

Session altered.

 

SQL> select * from test where object_id=60;

 

Execution Plan

----------------------------------------------------------

Plan hash value: 1235845473

 

------------------------------------------------------------------------------------------------

| Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                  |    11 |  2277 |     5   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST             |    11 |  2277 |     5   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_TEST_VIRTUAL |   263 |       |     1   (0)| 00:00:01 |

------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("OBJECT_ID"=60)

 

Note

-----

   - dynamic sampling used for this statement (level=2)

 

SQL> 

但是实际执行计划还是走全表扫描,如下测试。

SQL> set autotrace off;
SQL> select * from test where object_id=60;

...............

SQL> select sql_id, child_number,sql_text          

  2  from v$sql                                    

  3  where sql_text like ‘%select * from test%60%‘;

 

SQL_ID        CHILD_NUMBER SQL_TEXT

------------- ------------ ---------------------------------------

6t76zuzdgc4d9            0 select * from test where object_id=60

76rkkrw0j254p            0 select sql_id, child_number,sql_text from v$sql where sql_text like ‘%select * from test%60%‘

 

SQL> select * from table(dbms_xplan.display_cursor(‘6t76zuzdgc4d9‘));

 

PLAN_TABLE_OUTPUT

-----------------------------------------------------------------------

SQL_ID  6t76zuzdgc4d9, child number 0

-------------------------------------

select * from test where object_id=60

 

Plan hash value: 1357081020

 

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |       |       |   282 (100)|          |

|*  1 |  TABLE ACCESS FULL| TEST |    11 |  2277 |   282   (1)| 00:00:04 |

 

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("OBJECT_ID"=60)

 

Note

-----

   - dynamic sampling used for this statement (level=2)

 

 

22 rows selected.

查看数据库有没有创建对应的虚拟索引,可以使用下面SQL语句查询。

SELECT INDEX_OWNER, INDEX_NAME
  FROM DBA_IND_COLUMNS

 WHERE INDEX_NAME NOT LIKE ‘BIN$%‘

MINUS

SELECT OWNER, INDEX_NAME

  FROM DBA_INDEXES;

 

--或下面SQL(下面SQL在有些情况下有bug)

 

SELECT O.OBJECT_NAME AS FAKE_INDEX_NAME 

FROM   DBA_OBJECTS O 

WHERE  O.OBJECT_TYPE = ‘INDEX‘ 

       AND NOT EXISTS (SELECT NULL 

                       FROM   DBA_INDEXES I 

                       WHERE  O.OBJECT_NAME = I.INDEX_NAME 

                              AND O.OWNER = I.OWNER);

虚拟索引特点

虚拟索引跟普通索引是有所区别的。主要体现在下面一些地方。

1: 创建虚拟索引后需要设置隐含参数"_use_nosegment_indexes"为true, oracle才会选择虚拟索引。上面实验已经验证。

2: 虚拟索引只存在数据字典中定义,没有相关的索引段。如下所示,在dba_objects能查到索引定义,但是dba_indexes中没有数据。

SQL> select index_name from dba_indexes where table_name=‘TEST‘;
 

no rows selected

SQL> col object_name for a32;

SQL> col object_type for a32;

SQL> select object_name, object_type from dba_objects where object_name=upper(‘idx_test_virtual‘);

 

OBJECT_NAME                      OBJECT_TYPE

-------------------------------- --------------------------------

IDX_TEST_VIRTUAL                 INDEX

3: 虚拟索引也可以像普通索引那样分析analyze;但是没有相关统计信息生成(内部机制不清楚)

SQL> analyze index idx_test_virtual validate structure;
 

Index analyzed.

 

SQL> 

4: 虚拟索引不能重建rebuild,否则会抛出ORA-8114错误。

SQL> alter index idx_test_virtual rebuild;
alter index idx_test_virtual rebuild

*

ERROR at line 1:

ORA-08114: can not alter a fake index

5:不能创建与虚拟索引同名的普通索引

SQL> create index idx_test_virtual on test(object_id);
 

create index idx_test_virtual on test(object_id)

 

             *

 

ERROR at line 1:

 

ORA-00955: name is already used by an existing object

6:删除虚拟索引是不会放入到回收站的

SQL> show parameter recyclebin;
 

 

 

NAME                                 TYPE        VALUE

 

------------------------------------ ----------- ------------------------------

recyclebin                           string      on

 

SQL> drop index idx_test_virtual;

 

 

 

Index dropped.

 

SQL> select owner, object_name, original_name, type from dba_recyclebin

 

  2  where original_name=‘IDX_TEST_VIRTUAL‘;

 

 

 

no rows selected

参考资料:

Fake Indexes in Oracle RDBMS (文档 ID 329457.1)

Virtual Indexes (文档 ID 1401046.1)

时间: 2024-10-13 22:29:12

ORACLE虚拟索引(Virtual Index)的相关文章

Oracle虚拟索引的运用

在做SQL调优的时候,有的时候需要加一个索引,测试下对性能提升有没有帮组,如果此时这张表非常大,建索引将会非常之麻烦,这种场景虚拟索引就该登场了.下面来做个试验: SQL> select * from v$version; BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bi P

Oracle虚拟索引

从9.2版本开始Oracle引入了虚拟索引的概念,虚拟索引是一个"伪造"的索引,它的定义只存在数据字典中并有存在相关的索引段.虚拟索引是为了在不真正创建索引的情况下,验证如果使用索引sql执行计划是否改变,执行效率是否能得到提高. 本文在11.2.0.4版本中测试使用虚拟索引 1.创建测试表 [email protected]> create table test_t as select * from dba_objects; Table created. [email prot

【索引】Oracle之不可见索引和虚拟索引的比对

[索引]Oracle之不可见索引和虚拟索引的比对    Oracle之不可见索引 :http://blog.itpub.net/26736162/viewspace-2124044/ Oracle之虚拟索引 :  http://blog.itpub.net/26736162/viewspace-2123687/   之前给大家分享过不可见索引和虚拟索引,今天给大家分享的是Oracle之不可见索引和虚拟索引的比对.   比较项目 不可见索引(Invisible Indexes) 虚拟索引(Virt

利用虚拟索引(Virtual Index)优化数据库的案例分析

当我们在对生产库做优化的时候,主要就是对SQL语句的优化,包括语句的等价改写等,但其中很大一部分情况,又与索引有关.如果能合理利用合适的索引,可以使原本走全表扫描产生的逻辑读大大降低,提高数据库的性能.由于Oracle数据库中的索引本身就要占用磁盘空间,维护索引需要一定的开销,如何才能知道创建某个索引,会给数据带来性能的提升,而又不至于判断失误,创建了一个不恰当的索引,最后又不得不删除呢?这种情况下,我们可以利用Oralce提供的虚拟索引,即nosegment索引,它并不占用磁盘资源,只是在数据

Oracle 11g 虚拟列 Virtual Column介绍

Oracle 11G 虚拟列 Virtual Column Oracle 11G 在表中引入了虚拟列,虚拟列是一个表达式,在运行时计算,不存储在数据库中,不能更新虚拟列的值. 定义一个虚拟列的语法: column_name [datatype] [GENERATED ALWAYS] AS [expression] [VIRTUAL] 1.虚拟列可以用在select,update,delete语句的where条件中,但是不能用于DML语句 2.可以基于虚拟列来做分区 3. 可以在虚拟列上建索引,o

Oracle之索引(Index)实例讲解 - 基础

Oracle之索引(Index)实例讲解 - 基础 索引(Index)是关系数据库中用于存放表中每一条记录位置的一种对象,主要目的是加快数据的读取速度和数据的完整性检查.索引的建立是一项技术性要求非常高的工作. 一般在数据库设计阶段就要考虑到如何设计和创建索引. 1. 创建索引 创建索引的语法: CREATE [UNIQUE] INDEX [schema.] index ON [schema.] table (column [ASC | DESC], column [ASC | DESC]...

oracle唯一索引与普通索引的区别和联系以及using index用法

oracle唯一索引与普通索引的区别和联系 区别:唯一索引unique index和一般索引normal index最大的差异是在索引列上增加一层唯一约束.添加唯一索引的数据列可以为空,但是只要尊在数据值,就必须是唯一的. 联系:1)unique index就是额外添加唯一性的约束.该约束严格的保证索引列的取值是唯一的,这在一些数据列上的业务约束是很重要的功能.比如一个数据列,不能作为主键,而且允许为空,但是业务上要求唯一特性,这个时候用唯一性索引就是最好的旋转.2)性能上两者并无很大区别. u

Oracle 分区索引

分区索引(或索引分区)主要是针对分区表而言的.随着数据量的不断增长,普通的堆表需要转换到分区表,其索引呢,则对应的转换到分区索引.分区索引的好处是显而易见的.就是简单地把一个索引分成多个片断,在获取所需数据时,只需要访问更小的索引片断(块)即可实现.同时把分区放在不同的表空间可以提高分区的可用性和可靠性.本文主要描述了分区索引的相关特性并给出演示示例. 1.分区索引的相关概念a.分区索引的几种方式:表被分区而索引未被分区:表未被分区,而索引被分区:表和索引都被分区b.分区索引可以分为本地分区索引

Oracle 建立索引及SQL优化

Oracle 建立索引及SQL优化 数据库索引: 索引有单列索引 复合索引之说 如何某表的某个字段有主键约束和唯一性约束,则Oracle 则会自动在相应的约束列上建议唯一索引.数据库索引主要进行提高访问速度. 建设原则: 1.索引应该经常建在Where 子句经常用到的列上.如果某个大表经常使用某个字段进行查询,并且检索行数小于总表行数的5%.则应该考虑. 2.对于两表连接的字段,应该建立索引.如果经常在某表的一个字段进行Order By 则也经过进行索引. 3.不应该在小表上建设索引. 优缺点: