您的位置:首页 > 数据库 > Oracle

ORACLE虚拟索引(Virtual Index)

2017-09-15 16:10 411 查看
ORACLE虚拟索引(VirtualIndex)

虚拟索引概念

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

Avirtualindexisa"fake"indexwhosedefinitionexistsinthedatadictionary,buthasnoassociatedindexsegment.Thepurposeofvirtualindexesistosimulatetheexistenceofanindex-withoutactuallybuildingafullindex.Thisallowsdeveloperstorunanexplainplanasiftheindexispresentwithoutwaitingfortheindexcreationtocompleteandwithoutusingadditionaldiskspace.IfweobservethatoptimizeriscreatingaplanwhichisexpensiveandSQLtuningadvisorsuggestustocreateanindexonacolumn,incaseofproductiondatabaseitmaynotbealwaysfeasibletocreateanindexandtestthechanges.Weneedtomakesurethatthecreatedindexwillnothaveanynegativeimpactontheexecutionplanofotherqueriesrunninginthedatabase.Sohereiswhyavirtualindexcomesintopicture.

虚拟索引应用

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

虚拟索引测试

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

SQL>setlinesize1200
SQL>selectversionfromv$instance;
VERSION
-----------------
11.2.0.1.0
SQL>createtabletest
2as
3select*fromdba_objects;
Tablecreated.
SQL>setautotracetraceonlyexplain;
SQL>select*fromtestwhereobject_id=60;
ExecutionPlan
----------------------------------------------------------
Planhashvalue:1357081020
--------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------
|0|SELECTSTATEMENT||11|2277|282(1)|00:00:04|
|*1|TABLEACCESSFULL|TEST|11|2277|282(1)|00:00:04|
--------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
1-filter("OBJECT_ID"=60)
Note
-----
-dynamicsamplingusedforthisstatement(level=2)






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

SQL>setautotraceoff;
SQL>
SQL>createindexidx_test_virtualontest(object_id)nosegment;
Indexcreated.
SQL>setautotracetraceonlyexplain;
SQL>select*fromtestwhereobject_id=60;
ExecutionPlan
----------------------------------------------------------
Planhashvalue:1357081020
--------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------
|0|SELECTSTATEMENT||11|2277|282(1)|00:00:04|
|*1|TABLEACCESSFULL|TEST|11|2277|282(1)|00:00:04|
--------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
1-filter("OBJECT_ID"=60)
Note
-----
-dynamicsamplingusedforthisstatement(level=2)


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

SQL>altersessionset"_USE_NOSEGMENT_INDEXES"=true;
Sessionaltered.
SQL>select*fromtestwhereobject_id=60;
ExecutionPlan
----------------------------------------------------------
Planhashvalue:1235845473
------------------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
------------------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||11|2277|5(0)|00:00:01|
|1|TABLEACCESSBYINDEXROWID|TEST|11|2277|5(0)|00:00:01|
|*2|INDEXRANGESCAN|IDX_TEST_VIRTUAL|263||1(0)|00:00:01|
------------------------------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
2-access("OBJECT_ID"=60)
Note
-----
-dynamicsamplingusedforthisstatement(level=2)
SQL>






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

SQL>setautotraceoff;
SQL>select*fromtestwhereobject_id=60;
...............
SQL>selectsql_id,child_number,sql_text
2fromv$sql
3wheresql_textlike'%select*fromtest%60%';
SQL_IDCHILD_NUMBERSQL_TEXT
----------------------------------------------------------------
6t76zuzdgc4d90select*fromtestwhereobject_id=60
76rkkrw0j254p0selectsql_id,child_number,sql_textfromv$sqlwheresql_textlike'%select*fromtest%60%'
SQL>select*fromtable(dbms_xplan.display_cursor('6t76zuzdgc4d9'));
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
SQL_ID6t76zuzdgc4d9,childnumber0
-------------------------------------
select*fromtestwhereobject_id=60
Planhashvalue:1357081020
--------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
--------------------------------------------------------------------------
|0|SELECTSTATEMENT||||282(100)||
|*1|TABLEACCESSFULL|TEST|11|2277|282(1)|00:00:04|
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
1-filter("OBJECT_ID"=60)
Note
-----
-dynamicsamplingusedforthisstatement(level=2)
22rowsselected.


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

SELECTINDEX_OWNER,INDEX_NAME
FROMDBA_IND_COLUMNS
WHEREINDEX_NAMENOTLIKE'BIN$%'
MINUS
SELECTOWNER,INDEX_NAME
FROMDBA_INDEXES;
--或下面SQL(下面SQL在有些情况下有bug)
SELECTO.OBJECT_NAMEASFAKE_INDEX_NAME
FROMDBA_OBJECTSO
WHEREO.OBJECT_TYPE='INDEX'
ANDNOTEXISTS(SELECTNULL
FROMDBA_INDEXESI
WHEREO.OBJECT_NAME=I.INDEX_NAME
ANDO.OWNER=I.OWNER);






虚拟索引特点

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

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

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

SQL>selectindex_namefromdba_indexeswheretable_name='TEST';
norowsselected
SQL>colobject_namefora32;
SQL>colobject_typefora32;
SQL>selectobject_name,object_typefromdba_objectswhereobject_name=upper('idx_test_virtual');
OBJECT_NAMEOBJECT_TYPE
----------------------------------------------------------------
IDX_TEST_VIRTUALINDEX


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

SQL>analyzeindexidx_test_virtualvalidatestructure;
Indexanalyzed.
SQL>


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

SQL>alterindexidx_test_virtualrebuild;
alterindexidx_test_virtualrebuild
*
ERRORatline1:
ORA-08114:cannotalterafakeindex


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

SQL>createindexidx_test_virtualontest(object_id);
createindexidx_test_virtualontest(object_id)
*
ERRORatline1:
ORA-00955:nameisalreadyusedbyanexistingobject


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

SQL>showparameterrecyclebin;
NAMETYPEVALUE
-----------------------------------------------------------------------------
recyclebinstringon
SQL>dropindexidx_test_virtual;
Indexdropped.
SQL>selectowner,object_name,original_name,typefromdba_recyclebin
2whereoriginal_name='IDX_TEST_VIRTUAL';
norowsselected






参考资料:

FakeIndexesinOracleRDBMS(文档ID329457.1)

VirtualIndexes(文档ID1401046.1)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: