【DB笔试面试560】在Oracle中,虚拟列索引(Virtual Column Indexes)的作用是什么?
- 2019 年 10 月 10 日
- 筆記
♣
题目部分
在Oracle中,虚拟列索引(Virtual Column Indexes)的作用是什么?
♣
答案部分
在Oracle 11g之前的版本中,如果需要使用表达式或者一些计算公式,那么需要创建数据库视图;如果需要在这个视图上使用索引,那么会在表上创建基于函数的索引。虚拟列是Oracle 11g新引入的一项技术,虚拟列是一个表达式,在运行时计算,不存储在数据库中,不能更新虚拟列的值。使用虚拟列有如下好处:
① 可以收集虚拟列的统计信息,为CBO提供一定的采样分析。
② 可以在WHERE后面使用虚拟列作为选择条件。
③ 只在一处定义,不存储多余数据,查询时动态生成数据。
定义一个虚拟列的语法如下所示:
column_name [datatype] [GENERATED ALWAYS] AS [expression] [VIRTUAL]
下面给出虚拟列及虚拟列索引的语法示例:
CREATE TABLE T_VC_20170518_LHR2(VC_ID NUMBER, VC_COUNT NUMBER, VC_ALL GENERATED ALWAYS AS ( VC_ID + VC_COUNT ) VIRTUAL); CREATE INDEX VC_STATUS_IND2 ON T_VC_20170518_LHR2(VC_ALL);
虚拟列有如下特点:
① 在虚拟列的表达式中,可以包括同表的其它列、常量、SQL函数,甚至可以包括一些用户自定义的PL/SQL函数。
② 可以为虚拟列创建索引,称为虚拟列索引(实际上,Oracle为其创建的是函数索引),不能显式地为虚拟列创建函数索引。
③ 可以通过视图DBA_TAB_COLS的DATA_DEFAULT列来查询虚拟列的表达式,当创建了虚拟列索引(其实是一种函数索引)后,在视图DBA_IND_EXPRESSIONS中不能查询索引列。
④ 虚拟列的值并不是真实存在的,只有在用到时,才根据表达式计算出虚拟列的值,磁盘上并不存放虚拟列的数据。
⑤ 由于虚拟列的值由Oracle根据表达式自动计算得出,所以,虚拟列可以用在SELECT,UPDATE,DELETE语句的WHERE条件中,但是不能用于DML语句。
⑥ 可以基于虚拟列来做分区。
⑦ 可以在虚拟列上创建约束(例如主键)。
⑧ 只能在堆组织表(Heap-Organized Table,普通表)上创建虚拟列,不能在索引组织表、外部表、临时表上创建虚拟列。
⑨ 虚拟列值只能是标量,不能是其它类型(例如集合、LOB、RAW等类型)。
⑩ 可以把虚拟列当做分区关键字建立分区表,这是Oracle 11g的另一新特性称为虚拟列分区。
⑪ 在已经创建的表中增加虚拟列时,若没有指定虚拟列的字段类型,则Oracle会根据关键字“GENERATED ALWAYS AS”后面的表达式计算的结果自动设置该字段的数据类型。
⑫ 表达式中的所有列必须在同一张表。
⑬ 虚拟列表达式不能使用其它虚拟列。
下面给出虚拟列及虚拟列索引的使用示例:
LHR@orclasm > CREATE TABLE T_VC_20170518_LHR( 2 VC_ID NUMBER, 3 VC_COUNT NUMBER, 4 VC_STATUS GENERATED ALWAYS AS 5 (CASE WHEN VC_COUNT <= 100 THEN 'GETTING LOW' 6 WHEN VC_COUNT > 100 THEN 'OKAY' 7 END) 8 ); Table created. LHR@orclasm > DESC T_VC_20170518_LHR Name Null? Type ----------------------------------------- -------- ---------------------------- VC_ID NUMBER VC_COUNT NUMBER VC_STATUS VARCHAR2(11) LHR@orclasm > insert into T_VC_20170518_LHR (VC_ID, VC_COUNT) values (1, 100); 1 row created. LHR@orclasm > SELECT * FROM T_VC_20170518_LHR; VC_ID VC_COUNT VC_STATUS ---------- ---------- ----------- 1 100 GETTING LOW LHR@orclasm > ALTER TABLE T_VC_20170518_LHR ADD VC_COMM GENERATED ALWAYS AS(VC_COUNT * 0.1) VIRTUAL; Table altered. LHR@orclasm > DESC T_VC_20170518_LHR Name Null? Type ----------------------------------------- -------- ---------------------------- VC_ID NUMBER VC_COUNT NUMBER VC_STATUS VARCHAR2(11) VC_COMM NUMBER LHR@orclasm > SELECT * FROM T_VC_20170518_LHR; VC_ID VC_COUNT VC_STATUS VC_COMM ---------- ---------- ----------- ---------- 1 100 GETTING LOW 10 LHR@orclasm > alter table T_VC_20170518_LHR modify VC_STATUS generated always as( 2 case when VC_COUNT <= 50 then 'NEED MORE' 3 when VC_COUNT >50 and VC_COUNT <=200 then 'GETTING LOW' 4 when VC_COUNT > 200 then 'OKAY' 5 end); Table altered. LHR@orclasm > update T_VC_20170518_LHR set VC_COUNT=100 where VC_STATUS='OKAY'; 0 rows updated. LHR@orclasm > set line 9999 LHR@orclasm > col data_type format a10 LHR@orclasm > select table_name,COLUMN_NAME,data_type,data_default,VIRTUAL_COLUMN from user_tab_cols where table_name='T_VC_20170518_LHR'; TABLE_NAME COLUMN_NAME DATA_TYPE DATA_DEFAULT VIR ------------------------------ ------------------------------ ---------- -------------------------------------------------------------------------------- --- T_VC_20170518_LHR VC_ID NUMBER NO T_VC_20170518_LHR VC_COUNT NUMBER NO T_VC_20170518_LHR VC_STATUS VARCHAR2 CASE WHEN "VC_COUNT"<=50 THEN 'NEED MORE' WHEN ("VC_COUNT">50 AND "VC_COUNT"<=2 YES T_VC_20170518_LHR VC_COMM NUMBER "VC_COUNT"*0.1 YES T_VC_20170518_LHR VC_COMM2 NUMBER "VC_COUNT"*0.2 YES LHR@orclasm > alter table T_VC_20170518_LHR add (VC_comm2 as(VC_COUNT * 0.2) VIRTUAL); Table altered. LHR@orclasm > create index VC_STATUS_ind on T_VC_20170518_LHR(VC_STATUS); Index created. LHR@orclasm > select table_name,index_name,INDEX_TYPE from user_indexes where table_name='T_VC_20170518_LHR'; TABLE_NAME INDEX_NAME INDEX_TYPE ------------------------------ ------------------------------ --------------------------- T_VC_20170518_LHR VC_STATUS_IND FUNCTION-BASED NORMAL
& 说明:
有关虚拟列的更多内容可以参考我的BLOG:http://blog.itpub.net/26736162/viewspace-2139258/
其它索引
应用程序域索引(Application Domain Indexes)是由用户为一个特定的应用程序域中的数据创建的。其物理索引不需要使用传统的索引结构,可以存储为Oracle数据库表,或外部文件。应用程序域索引是一个特定于应用程序的自定义索引。
对于B-Tree簇索引(B-Tree Cluster Indexes)和哈希聚簇索引(Hash Cluster Indexes)本书不再详解,对此感兴趣的读者可以参考相关的官方文档。
本文选自《Oracle程序员面试笔试宝典》,作者:李华荣。