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-08 21:06:26

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

ZT:关于虚拟索引(Virtual Index)

http://www.itpub.net/showthread.php?s=&postid=7523115#post7523115 在数据库优化中,索引的重要性不言而喻.但是,在性能调整过程中,一个索引是否能被查询用到,在索引创建之前是无法确定的,而创建索引是一个代价比较高的操作,尤其是数据量较大的时候. 虚拟索引不是物理存在的,它并不会创建实际的索引段,只是在数据字典中加了一个索引的记录,使得优化器能够意识到一个索引的存在,从而判断是否使用该索引作为访问路径.当然,实际上最终查询的访问路径是不

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

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

关于Oracle 9i 跳跃式索引扫描(Index Skip Scan)的小测试

oracle|索引 在Oracle9i中我们知道能够使用跳跃式索引扫描(Index Skip Scan).然而,能利用跳跃式索引扫描的情况其实是有些限制的. 从Oracle的文档中我们可以找到这样的话: Index Skip ScansIndex skip scans improve index scans by nonprefix columns. Often, scanning index blocks is faster than scanning table data blocks.Sk

Oracle技术:使用Index提示强制使用索引

虽然索引并不总会快于全表扫描,但是很多时候我们希望Oracle使用索引来执行某些SQL,这时候我们可以通过index hints来强制SQL使用index. Index Hints的格式如下: /*+ INDEX ( table [index [index]...] ) */我们简单看一下这个提示的用法(范例为Oracle10g数据库): SQL> create table t as select username,password from dba_users;Table created.SQ

PostgreSQL 虚拟|虚假 索引(hypothetical index) - HypoPG

标签 PostgreSQL , 虚拟索引 , 虚假索引 , HypoPG , hypothetical index 背景 DBA实际上是一种比较稀缺的资源,很多企业甚至没有DBA,或者SA.开发人员兼职DBA,对于一般的使用者,对数据库了解程度有限,特别是在SQL优化方面的知识更加有限. 最常用也是奏效较快的SQL优化手段,通常是加索引,这也是我从很多开发者交流后得知的,很多人的概念是,SQL慢,加索引嘛. 但是加索引有没有效果要针对"SQL.针对数据分布.针对输入条件.针对列的唯一值比例&qu

[20120903]关于Virtual index.txt

[20120903]关于Virtual index.txt         virtual index没有segment,如何去产生该虚拟索引的统计信息,如何保证CBO的有效判断. 做一个测试与学习看看: 1.测试环境: SQL> select * from v$version ; BANNER ------------------------------------------------------------------------------ Oracle Database 11g En

[20130815]关于虚拟索引的问题.txt

[20130815]关于虚拟索引的问题.txt 虚拟索引建立并没有占用磁盘空间,主要用来评估建立的索引是否可用.但是存在一个问题,如果建立了这样的索引,dba如何知道目前数据库存在那些虚拟索引,做一个例子来说明: 1.建立测试环境: SQL> @ver BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edit

Oracle管理索引(四)Oracle修改索引

1.修改索引段存储参数 03:31:28 SQL> alter index scott.indx_ename deallocate unused; Index altered. 03:31:36 SQL> alter index scott.indx_ename allocate extent(size 1m); Index altered. 2.重建索引 03:32:48 SQL> alter index indx_ename rebuild; Index altered. 3.联机重

Oracle监控索引怎么使用

Oracle监控索引使用   Oracle提供一个监控索引的方法,来确定索引是否被使用.如果索引没有被使用,就可以删除它们以减少不必要的语句的开销.因为表上的大量不必要的索引可能会降低DML语句的性能,给数据库性能产生压力.所以生产环境上,以根据业务增长情况定期监控.分析数据库索引的使用,特别是一些大表上的索引,提升数据库事务提交的性能.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 --查看表上的索引 SQL> Selectindex