虚拟索引是定义在数据字典中的伪索引,但没有相关的索引段。虚拟索引的目的是模拟索引的存–而不用真实的创建一个完整索引。这允许开发者创建虚拟索引来查看相关执行计划而不用等到真实创建完索引才能查看索引对执行计划的影响,并且不会增加存储空间的使用。如果我们观察到优化器生成了一个昂贵的执行计划并且SQL调整指导建议我们对某些的某列创建索引,但在生产数据库环境中创建索引与测试并不总是可以操作。我们需要确保创建的索引将不会对数据库中的其它查询产生负面影响,因此可以使用虚拟索引。
下面举例进行说明:
1.创建一个测试表test
SQL>createtabletestasselect*fromdba_objects; Table created.
2.从表test查询object_name等于standard的记录
SQL>select*fromtestwhereobject_name='STANDARD'; OWNER ------------------------------ OBJECT_NAME -------------------------------------------------------------------- SUBOBJECT_NAMEOBJECT_IDDATA_OBJECT_IDOBJECT_TYPE ----------------------------------------------------------------- CREATEDLAST_DDL_TIMTIMESTAMPSTATUSTGS ----------------------------------------------------- SYS STANDARD 888PACKAGE 19-APR-1019-APR-102003-04-18:00:00:00VALIDNNN OWNER ------------------------------ OBJECT_NAME -------------------------------------------------------------------- SUBOBJECT_NAMEOBJECT_IDDATA_OBJECT_IDOBJECT_TYPE ------------------------------------------------------------------------- CREATEDLAST_DDL_TIMTIMESTAMPSTATUSTGS ----------------------------------------------------- SYS STANDARD 889PACKAGEBODY 19-APR-1019-APR-102010-04-19:10:22:58VALIDNNN
3.查询上面查询的执行计划
SQL>setautotracetraceonlyexplain SQL>select*fromtestwhereobject_name='STANDARD'; ExecutionPlan ---------------------------------------------------------- Planhashvalue:1357081020 -------------------------------------------------------------------------- |Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time| -------------------------------------------------------------------------- |0|SELECTSTATEMENT||8|1416|155(1)|00:00:02| |*1|TABLEACCESSFULL|TEST|8|1416|155(1)|00:00:02| -------------------------------------------------------------------------- PredicateInformation(identifiedbyoperationid): --------------------------------------------------- 1-filter("OBJECT_NAME"='STANDARD') Note ----- -dynamicsamplingusedforthisstatement
4.在表test的object_name列上创建一个虚拟索引
SQL>createindextest_indexontest(object_name)nosegment;Indexcreated.
为了创建虚拟索引必须在create index语句中指定nosegment子句,并且不会创建索引段。
5.来验证虚拟索引不会创建索引段
SQL>setautotraceoff SQL>selectindex_namefromdba_indexeswheretable_name='TEST'andindex_name='TEST_INDEX'; norowsselected SQL>colOBJECT_NAMEformata20; SQL>selectobject_name,object_typefromdba_objectswhereobject_name='TEST_INDEX'; OBJECT_NAMEOBJECT_TYPE --------------------------------------- TEST_INDEXINDEX
从上面的结果可以看到索引对象已经创建,但没有创建索引段。
6.重新执行sql查看创建的虚拟索引是否被使用
SQL>setautotracetraceonlyexplainSQL>select*fromtestwhereobject_name='STANDARD'; ExecutionPlan ---------------------------------------------------------- Planhashvalue:1357081020 -------------------------------------------------------------------- |Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time| -------------------------------------------------------------------- |0|SELECTSTATEMENT||8|1416|155(1)|00:00:02| |*1|TABLEACCESSFULL|TEST|8|1416|155(1)|00:00:02| -------------------------------------------------------------------- PredicateInformation(identifiedbyoperationid): --------------------------------------------------- 1-filter("OBJECT_NAME"='STANDARD') Note ----- -dynamicsamplingusedforthisstatement
从上面的执行计划可以清楚地看到创建的虚拟索引并没有被使用。
7.为了能使用所创建的虚拟索引,需要将_USE_NOSEGMENT_INDEXES设置为true
SQL>altersessionset"_USE_NOSEGMENT_INDEXES"=true;Sessionaltered.
8.重新执行sql查看创建的虚拟索引是否被使用
SQL>setlong900SQL>setlinesize900 SQL>select*fromtestwhereobject_name='STANDARD'; ExecutionPlan ---------------------------------------------------------- Planhashvalue:2627321457 -------------------------------------------------------------------- |Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time| -------------------------------------------------------------------- |0|SELECTSTATEMENT||8|1416|5(0)|00:00:01| |1|TABLEACCESSBYINDEXROWID|TEST|8|1416|5(0)|00:00:01| |*2|INDEXRANGESCAN|TEST_INDEX|238||1(0)|00:00:01| -------------------------------------------------------------------- PredicateInformation(identifiedbyoperationid): --------------------------------------------------- 2-access("OBJECT_NAME"='STANDARD') Note ----- -dynamicsamplingusedforthisstatement
从上面的执行计划可以看到当设置隐含参数_USE_NOSEGMENT_INDEXES后,优化器将会使用创建的虚拟索引。在使用虚拟索引需要注意,我们可以分析虚拟索引,但不能重建虚拟索引,如果重建虚拟索引会收到ORA-8114: "User attempted to alter a fake index"错误提示,可以删除虚拟索引。