1 嵌套表语法
下面使用简单的EMP和DEPT表来说明:
system@ORCL>create table dept_0619
2 (deptno number(2) primary key,
3 dname varchar2(14),
4 loc varchar2(13)
5 );
表已创建。
system@ORCL>create table emp_0619
2 (empno number(4) primary key,
3 ename varchar2(10),
4 job varchar2(9),
5 mgr number(4) references emp_0619,
6 hiredate date,
7 sal number(7, 2),
8 comm number(7, 2),
9 deptno number(2) references dept_0619
10 );
表已创建。
这里有主键和外键。下面建立与之对应的等价实现,不过这里EMP表实现为嵌套表:
system@ORCL>create or replace type emp_type
2 as object
3 (empno number(4),
4 ename varchar2(10),
5 job varchar2(9),
6 mgr number(4),
7 hiredate date,
8 sal number(7, 2),
9 comm number(7, 2)
10 );
11 /
类型已创建。
system@ORCL>create or replace type emp_tab_type
2 as table of emp_type
3 /
类型已创建。
要创建一个带嵌套表的表,需要有一个嵌套表类型。以上代码创建了一个复杂的对象类型EMP_TYPE,并创建了它的一个嵌套表类型 EMP_TAB_TYPE。在PL/SQL中,会像处理数组一样处理这种类型。在SQL中,这会导致创建一个物理的嵌套表。以下简单的CREATE TABLE语句使用了这个类型:
system@ORCL>create table dept_and_emp
2 (deptno number(2) primary key,
3 dname varchar2(14),
4 loc varchar2(13),
5 emps emp_tab_type
6 )
7 nested table emps store as emps_nt;
表已创建。
system@ORCL>alter table emps_nt add constraint
2 emps_empno_unique unique(empno)
3 /
表已更改。
这 个CREATE TABLE语句中重要的是:其中包括列EMPS(类型为EMP_TAB_TYPE),还有相应的NESTED TABLE EMPS STORE AS EMPS_NT。这样除了表DEPT_AND_EMP之外,还会创建一个真正的物理表EMPS_NT,这个表与DEPT_AND_EMP是分开的。我们的 嵌套表的EMPNO列上直接加了一个约束,使EMPNO像在原来的关系模型中一样是惟一的。利用嵌套表无法实现前面完整的数据模型:关系模型中存在自引用 约束,倘若在嵌套表上增加同样的约束,则有:
system@ORCL>alter table emps_nt add constraint mgr_fk
2 foreign key(mgr) references emps_nt(empno);
alter table emps_nt add constraint mgr_fk
*
第 1 行出现错误:
ORA-30730: 嵌套表列中不支持引用约束条件
这是不行的。嵌套表不支持引用完整性约束,因为它们不能引用任何表,甚至它们自己。接下来,用现有的EMP和DEPT数据来填充这个表:
system@ORCL>insert into dept_and_emp
2 select dept.*,
3 CAST( multiset( select empno, ename, job, mgr, hiredate, sal, comm
4 from SCOTT.EMP
5 where emp.deptno = dept.deptno ) AS emp_tab_type )
6 from SCOTT.DEPT
7 /
已创建4行。
这里有两点要注意:
q 只创建了“4”行。DEPT_AND_EMP表中确实只有4行。没有独立地存在14个EMP行。
q MULTISET关键字用于告诉Oracle:这个子查询返回多行(SELECT列表中的子查询先前限制为只返回一行)。CAST用于指示Oracle: 要把返回的结果集处理为一个集合类型,在这里,我们将MULTISET强制转换(CAST)为一个EMP_TAB_TYPE。CAST是一个通用的例程, 并不仅限于在集合中使用。例如,如果想从EMP中将EMPNO列获取为VARCHAR2(20)而不是NUMBER(4)类型,可以使用以下查询:SELECT CAST(EMPNO AS VARCHAR2(20)) E FROM EMP。
现在可以查询数据了。下面来看一行是什么样子:
system@ORCL>select deptno, dname, loc, d.emps AS employees
2 from dept_and_emp d
3 where deptno = 10
4 /
DEPTNO DNAME LOC
---------- -------------- -------------
EMPLOYEES(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------------------------------
10 accounting NEW YORK
EMP_TAB_TYPE(EMP_TYPE(7782, 'CLARK', 'MANAGER', 7839, '09-6月 -81', 76629, NULL)
, EMP_TYPE(7839, 'KING', 'PRESIDENT', NULL, '17-11月-81', 79179, NULL), EMP_TYPE
(7934, 'MILLER', 'CLERK', 7782, '23-1月
-82', 75479, NULL))
现 有数据都在这里,都放在一个列中。大多数应用都不能处理这个特殊的列,除非是专门针对对象关系特性编写的。例如,ODBC没有办法处理嵌套表。针对这些情况,Oracle提供了一种方法,可以取消集合的嵌套,把它当成一个关系 表来处理:
system@ORCL>select d.deptno, d.dname, emp.*
2 from dept_and_emp D, table(d.emps) emp
3 /
DEPTNO DNAME EMPNO ENAME JOB MGR HIREDATE
SAL COMM
---------- -------------- ---------- ---------- --------- ---------- -----------
--- ---------- ----------
10 accounting 7782 CLARK MANAGER 7839 09-6月 -81
76629
10 accounting 7839 KING PRESIDENT 17-11月-81
79179
10 accounting 7934 MILLER CLERK 7782 23-1月 -82
75479
20 RESEARCH 7369 SMITH CLERK 7902 17-12月-80
74979
20 RESEARCH 7566 JONES MANAGER 7839 02-4月 -81
77154
20 RESEARCH 7788 SCOTT ANALYST 7566 19-4月 -87
77179
20 RESEARCH 7876 ADAMS CLERK 7788 23-5月 -87
75279
20 RESEARCH 7902 FORD ANALYST 7566 03-12月-81
77179
30 SALES 7499 ALLEN SALESMAN 7698 20-2月 -81
75779 300
30 SALES 7521 WARD SALESMAN 7698 22-2月 -81
75429 500
30 SALES 7654 MARTIN SALESMAN 7698 28-9月 -81
75429 1400
30 SALES 7698 BLAKE MANAGER 7839 01-5月 -81
77029
30 SALES 7844 TURNER SALESMAN 7698 08-9月 -81
75679 0
30 SALES 7900 JAMES CLERK 7698 03-12月-81
75129
已选择14行。
可以把EMPS列强制转换为一个表,它会自然地为我们完成联结,这里不需要联结条件。实际上,由于我们的EMP类型根本没有DEPTNO列,所以无法明确地在哪个列上完成联结。这些杂事都由Oracle为我们做。
那么,怎么更新数据呢?假设我们想给部门10发$100的奖金。可以如下编写代码:
system@ORCL>update
2 table( select emps
3 from dept_and_emp
4 where deptno = 10
5 )
6 set comm = 100
7 /
已更新3行。
前面说过“每一行都有一个虚拟的表”,UPDATE语句能很清楚地显示出每行有一个表。我们选择一个具体的表来更新(UPDATE)——这个表没有名字, 只是用一个查询来标识。如果使用的这个查询不是刚好选择(SELECT)一个表,我们就会得到以下错误:
system@ORCL>update
2 table( select emps
3 from dept_and_emp
4 where deptno = 1
5 )
6 set comm = 100
7 /
update
*
第 1 行出现错误:
ORA-22908: NULL 表值的参考
system@ORCL>update
2 table( select emps
3 from dept_and_emp
4 where deptno > 1
5 )
6 set comm = 100
7 /
table( select emps
*
第 2 行出现错误:
ORA-01427: 单行子查询返回多个行
如果返回至少一行(一个嵌套表实例也没有),更新就会失败。正常情况下,更新0行是可以的,但在这里不行,它会返回一个错误,就好像我们的更新中漏写了表名 一样。如果返回了多行(不止一个嵌套表实例),更新也会失败。正常情况下,更新多行是完全可以的。但是这里显示出,Oracle认为 DEPT_AND_EMP表中的每一行指向另一个表,而不是像关系模型中那样指定另外一个行集。
这 就是嵌套表和父/子关系表之间的语义差别。在嵌套表模型中,每个父行有一个表。而关系模型中,每个父行有一个行集。这种差别使用嵌套表有时使用起来有些麻 烦。考虑我们使用的这个模型,它从单个部门的角度提供了一个很好的数据视图。如果我们想问“KIND为哪个部门工作?”“有多少在职的会计”等待,这个模 型就很糟糕了。这些问题最好去问EMP关系表,而在嵌套表模型中,我们只能通过DEPT数据来访问EMP数据。总是必须联结,而无法单独地查询EMP数据。在这方面,Oracle没有提供公开支持的方法(也没有相关的文档说明),但是我们可以使用一个技巧来完成。如果需要更新EMPS_NT中的每一行,我们必须完成4个更新:分别更新DEPT_AND_EMP中的各行,从而更新与之关联的虚拟表。
更新部门10的员工数据时,还有考虑一个问题,我们是在语义上更新DEPT_AND_EMP表中的EMPS列。要知道,尽管在物理上涉及两个表,但是语义上 只有一个表。即使我们没有更新部门表中的数据,包含所修改嵌套表的行也会被锁定,不允许其他会话更新。传统的父/子表关系中则不是这样。
正是由于这些原因,不主张把嵌套表用作一种持久存储机制。作为子表,如果不用单独查询,这种情况实在是少见。在前面的例子中,EMP表应该是一个强实体。它是独立的,所以需要单独查询,通过关系表上的视图来使用嵌套表。
下面向嵌套表实例部门10增加一行,再从部门20删除一行:
system@ORCL>insert into table
2 ( select emps from dept_and_emp where deptno = 10 )
3 values
4 ( 1234, 'NewEmp', 'CLERK', 7782, sysdate, 1200, null );
已创建 1 行。
system@ORCL>delete from table
2 ( select emps from dept_and_emp where deptno = 20 )
3 where ename = 'SCOTT';
已删除 1 行。
system@ORCL>select d.dname, e.empno, ename
2 from dept_and_emp d, table(d.emps) e
3 where d.deptno in ( 10, 20 );
DNAME EMPNO ENAME
-------------- ---------- ----------
accounting 7782 CLARK
accounting 7839 KING
accounting 7934 MILLER
accounting 1234 NewEmp
RESEARCH 7369 SMITH
RESEARCH 7566 JONES
RESEARCH 7876 ADAMS
RESEARCH 7902 FORD
已选择8行。
这就是查询和修改嵌套表的基本语法。必须像刚才那样取消这些表的嵌套(特别是在查询中),才能使用这些嵌套表。一旦从概念上了解了“每行一个虚拟表”的概念,使用嵌套表就会容易得多。
前面我说过,“总是必须联结;而无法单独地查询EMP数据”,但是然后我又告诫说“如果你确实需要,(利用一个技巧)这也是能办到的”。如果你确实需要大批量地更新嵌套表(记住,要利用联结通过DEPT表来做到),此时这种 方法才能最好地发挥作用。Oracle中有一个无文档说明的提示: NESTED_TABLE_GET_REFS,许多工具都使用了这个提示,如EXP和IMP就利用了这个提示来处理嵌套表。利用这种方法还可以查看嵌套表 物理结构的更多信息。使用这个提示,可以完成查询来得到一些“神奇”的结果。EXP(一个数据卸载工具)从嵌套表中抽取数据时就使用了以下查询:
system@ORCL>SELECT /*+NESTED_TABLE_GET_REFS*/
2 NESTED_TABLE_ID,SYS_NC_ROWINFO$
3 FROM EMPS_NT
4 /
NESTED_TABLE_ID
--------------------------------
SYS_NC_ROWINFO$(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------------------------------
661C14D4BEAA4F5C9F216609B63C052C
EMP_TYPE(7782, 'CLARK', 'MANAGER', 7839, '09-6月 -81', 76629, 100)
661C14D4BEAA4F5C9F216609B63C052C
EMP_TYPE(7839, 'KING', 'PRESIDENT', NULL, '17-11月-81', 79179, 100)
661C14D4BEAA4F5C9F216609B63C052C
EMP_TYPE(7934, 'MILLER', 'CLERK', 7782, '23-1月 -82', 75479, 100)
A4A900ECCFDD4F24BFE50A248DEF7059
EMP_TYPE(7369, 'SMITH', 'CLERK', 7902, '17-12月-80', 74979, NULL)
A4A900ECCFDD4F24BFE50A248DEF7059
EMP_TYPE(7566, 'JONES', 'MANAGER', 7839, '02-4月 -81', 77154, NULL)
A4A900ECCFDD4F24BFE50A248DEF7059
EMP_TYPE(7876, 'ADAMS', 'CLERK', 7788, '23-5月 -87', 75279, NULL)
A4A900ECCFDD4F24BFE50A248DEF7059
EMP_TYPE(7902, 'FORD', 'ANALYST', 7566, '03-12月-81', 77179, NULL)
56C2FF23448D4CC79020E0D292AEED37
EMP_TYPE(7499, 'ALLEN', 'SALESMAN', 7698, '20-2月 -81', 75779, 300)
56C2FF23448D4CC79020E0D292AEED37
EMP_TYPE(7521, 'WARD', 'SALESMAN', 7698, '22-2月 -81', 75429, 500)
56C2FF23448D4CC79020E0D292AEED37
EMP_TYPE(7654, 'MARTIN', 'SALESMAN', 7698, '28-9月 -81', 75429, 1400)
56C2FF23448D4CC79020E0D292AEED37
EMP_TYPE(7698, 'BLAKE', 'MANAGER', 7839, '01-5月 -81', 77029, NULL)
56C2FF23448D4CC79020E0D292AEED37
EMP_TYPE(7844, 'TURNER', 'SALESMAN', 7698, '08-9月 -81', 75679, 0)
56C2FF23448D4CC79020E0D292AEED37
EMP_TYPE(7900, 'JAMES', 'CLERK', 7698, '03-12月-81', 75129, NULL)
661C14D4BEAA4F5C9F216609B63C052C
EMP_TYPE(1234, 'NewEmp', 'CLERK', 7782, '20-6月 -18', 1200, NULL)
已选择14行。
但是,如果描述这个嵌套表,会有点奇怪:
system@ORCL>desc emps_nt
名称
是否为空? 类型
-------------------------------------------------------------------------------
---------------------------------- -------- ------------------------------------
----------------------------------------
EMPNO
NUMBER(4)
ENAME
VARCHAR2(10)
JOB
VARCHAR2(9)
MGR
NUMBER(4)
HIREDATE
DATE
SAL
NUMBER(7,2)
COMM
NUMBER(7,2)
前面查询的两列居然没有出现。它们是嵌套表隐藏实现的一部分。NESTED_TABLE_ID实际上是父表DEPT_AND_EMP的一个外键。 DEPT_AND_EMP中确实有一个隐藏列,用于联结至EMPS_NT。SYS_NC_ROWINFO$“列”是一个神奇的列;它更应该算是一个函数而 不是一个列。这里的嵌套表实际上是一个对象表(由一个对象类型组成),而SYS_NC_ROWINFO$正是Oracle将行引用为对象所采用的内部方法,而并非引用行的各个标量列。在底层,Oracle会用系统生成的主键和外键实现一个父/子表。如果更进一步挖掘,可以查询“真正”的数据字典来查看 DEPT_AND_EMP表中的所有列:
select name
from sys.col$
where obj# = ( select object_id
from dba_objects
where object_name = 'DEPT_AND_EMP'
and owner = 'system@ORCL' )
/
NAME
------------------------------
DEPTNO
DNAME
EMPS
LOC
SYS_NC0000400005$
从嵌套表中选出这一列,我们会看到下面的结果:
select SYS_NC0000400005$ from dept_and_emp;
SYS_NC0000400005$
--------------------------------
F60DEEE0FF887BC1E030007F01001321
F60DEEE0FF897BC1E030007F01001321
F60DEEE0FF8A7BC1E030007F01001321
F60DEEE0FF8B7BC1E030007F01001321
这 个列名看上去很古怪(SYS_NC0000400005$),这是放在DEPT_AND_EMP表中的系统生成的键。如果更深层次地挖掘,会发现 Oracle已经在这个列上放上了惟一一个索引。不过,遗憾的是,它没有对EMP_NT中的NESTED_TABLE_ID加索引。这个列确实需要加索 引,因为我们总是要从DEPT_AND_EMP联结到EMPS_NT。如果像刚才那样使用默认值,必须记住关于嵌套表的一个要点:一定要对嵌套表中的 NESTED_TABLE_ID加索引!
如何把嵌套表当成一个真正的表来进行处理。NESTED_TABLE_GET_REFS提示就为我们做了这个工作。可以使用如下的提示:
system@ORCL>select /*+ nested_table_get_refs */ empno, ename
2 from emps_nt where ename like '%A%';
EMPNO ENAME
---------- ----------
7782 CLARK
7876 ADAMS
7499 ALLEN
7521 WARD
7654 MARTIN
7698 BLAKE
7900 JAMES
已选择7行。
system@ORCL>update /*+ nested_table_get_refs */ emps_nt
2 set ename = initcap(ename);
已更新14行。
system@ORCL>select /*+ nested_table_get_refs */ empno, ename
2 from emps_nt where ename like '%a%';
EMPNO ENAME
---------- ----------
7782 Clark
7876 Adams
7521 Ward
7654 Martin
7698 Blake
7900 James
已选择6行。
再 次重申,这个特性没有相关的文档说明,没有得到公开支持。它是一个保障EXP和IMP工作的特定功能,而且只有在EXP和IMP环境中才能保证这种方法一 定可行。你自己使用时会有风险,而且千万不要用在生成代码中。实际上,如果你发现确实需要使用这个特性,那么从定义来讲,这说明根本就不应该使用嵌套表! 这个结构对你完全不适合。可以用这种方法对数据完成一次性修正,或者你对嵌套表很好奇,可以通过这个技巧来看看嵌套表里有什么。要报告嵌套表中的数据,公 开支持的方法是消除嵌套,如下:
system@ORCL>select d.deptno, d.dname, emp.*
2 from dept_and_emp D, table(d.emps) emp
3 /
DEPTNO DNAME EMPNO ENAME JOB MGR HIREDATE
SAL COMM
---------- -------------- ---------- ---------- --------- ---------- -----------
--- ---------- ----------
10 accounting 7782 Clark MANAGER 7839 09-6月 -81
76629 100
10 accounting 7839 King PRESIDENT 17-11月-81
79179 100
10 accounting 7934 Miller CLERK 7782 23-1月 -82
75479 100
10 accounting 1234 Newemp CLERK 7782 20-6月 -18
1200
20 RESEARCH 7369 Smith CLERK 7902 17-12月-80
74979
20 RESEARCH 7566 Jones MANAGER 7839 02-4月 -81
77154
20 RESEARCH 7876 Adams CLERK 7788 23-5月 -87
75279
20 RESEARCH 7902 Ford ANALYST 7566 03-12月-81
77179
30 SALES 7499 Allen SALESMAN 7698 20-2月 -81
75779 300
30 SALES 7521 Ward SALESMAN 7698 22-2月 -81
75429 500
30 SALES 7654 Martin SALESMAN 7698 28-9月 -81
75429 1400
30 SALES 7698 Blake MANAGER 7839 01-5月 -81
77029
30 SALES 7844 Turner SALESMAN 7698 08-9月 -81
75679 0
30 SALES 7900 James CLERK 7698 03-12月-81
75129
已选择14行。
2 嵌套表存储
system@ORCL>create table dept_and_emp
2 (deptno number(2) primary key,
3 dname varchar2(14),
4 loc varchar2(13),
5 emps emp_tab_type
6 )
7 nested table emps store as emps_nt;
表已创建。
system@ORCL>alter table emps_nt add constraint emps_empno_unique
2 unique(empno)
3 /
表已更改。
这个代码创建了两个实际的表。这里确实会创建我们请求创建的表,但是它有额外的一个隐藏列(默认情况下,对于表中的每一个嵌套表列,都会有一个额外的隐藏 列)。它还在这个隐藏列上创建了一个惟一约束。Oracle为我们创建了嵌套表EMPS_NT。这个表有两个隐藏列,其中的SYS_NC_ROWINFO $列并不真正算是一个列,而应该是一个虚拟列,它会把所有标量元素返回为一个对象。另一个隐藏列是名为NESTED_TABLE_ID的外键,通过这个外键可以联结回父表。注意这个列上没有索引。最后,Oracle在DEPT_AND_EMP表的DEPTNO列上增加了一个索引,以保证主键。所以,我们本来只请求创建一个表,得到的却远不止一个表。如果查看这个表,与创建父/子关系时所看到的情况非常相似,但是你要使用DEPTNO上的现有主键作为 EMPS_NT的外键,而不是生成一个代理键RAW(16)。
如果查看嵌套表示例的DBMS_METADATA.GET_DDL转储信息,可以看到以下内容:
system@ORCL>begin
2 dbms_metadata.set_transform_param
3 ( DBMS_METADATA.SESSION_TRANSFORM, 'STORAGE', false );
4 end;
5 /
PL/SQL 过程已成功完成。
system@ORCL>select dbms_metadata.get_ddl( 'TABLE', 'DEPT_AND_EMP' ) from dual;
DBMS_METADATA.GET_DDL('TABLE','DEPT_AND_EMP')
--------------------------------------------------------------------------------
CREATE TABLE "SYSTEM"."DEPT_AND_EMP"
( "DEPTNO" NUMBER(2,0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
"EMPS" "SYSTEM"."EMP_TAB_TYPE" ,
PRIMARY KEY ("DEPTNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
TABLESPACE "SYSTEM" ENABLE
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
TABLESPACE "SYSTEM"
NESTED TABLE "EMPS" STORE AS "EMPS_NT"
(( CONSTRAINT "EMPS_EMPNO_UNIQUE" UNIQUE ("EMPNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
TABLESPACE "SYSTEM" ENABLE)
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 LOGGING
TABLESPACE "SYSTEM" ) RETURN AS VALUE
到此为止,只有一个新内容,即RETURN AS VALUE。 这个选项用于描述如何向客户应用返回嵌套表。默认情况下,Oracle会按值把嵌套表返回给客户:具体数据会随各行传输。这个选项也可以设置为 RETURN AS LOCATOR,这说明客户会得到指向数据的一个指针,而不是数据本身。当且仅当客户对这个指针解除引用(dereference)时,才会把数据传输给客户。因此,如果你相信客户通常不会查看对应各个父行的嵌套表(不会查看这些嵌套表中的行),就可以返回一个locator而不是值,这样可以节省网络往返通信开销。例如,如果你的客户应用要显示部门列表,当用户双击一个部门时,客户应用会显示出员工信息,你就可以考虑使用locator。这是因为通常都 不会查看详细信息,查看详细信息的情况是例外,而不是一般情况。
那么,我们还能对嵌套表做些什么呢?首先,NESTED_TABLE_ID列必须建立索引。因为我们总是从父表联结到子表来访问嵌套表,我们确实需要这个索引。可以使用CREATE INDEX对该列建立索引,但是最好的解决方案是使用一个IOT来存储嵌套表。嵌套表也是一个适用IOT的绝好例子。它会按 NESTED_TABLE_ID将子行物理地共同存储在一块(所以用最少的物理I/O就能完成表的获取),这样就不必在RAW(16)列上建立冗余的索 引。再前进一步,由于NESTED_TABLE_ID就是IOT主键的第一列,还应该加入索引键压缩来避免冗余的NESTED_TABLE_ID(否则会 重复存储)。另外,我们还可以在CREATE TABLE命令中加入EMPNO列的UNIQUE和NOT NULL约束。因此,对于前面的CREATE TABLE,可以稍作修改,如下所示:
CREATE TABLE "SYSTEM"."DEPT_AND_EMP"
("DEPTNO" NUMBER(2, 0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
"EMPS" "EMP_TAB_TYPE")
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 LOGGING
STORAGE(INITIAL 131072 NEXT 131072
MINEXTENTS 1 MAXEXTENTS 4096
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
NESTED TABLE "EMPS"
STORE AS "EMPS_NT"
( (empno NOT NULL, unique (empno), primary key(nested_table_id,empno))
organization index compress 1 )
RETURN AS VALUE
/
如果EMPS_NT是一个使用压缩的IOT,它比原来默认嵌套表占用的存储空间更少,而且其中有我们非常需要的索引。
3嵌套表小结
不建议把嵌套表用作一种持久存储机制,原因如下:
q 这样会增加不必要的RAW(16)列存储开销。父表和子表都有这个额外的列。父表对于其中的各个嵌套表列都有一个额外的16字节RAW字段。由于父表通常已经有一个主键(在我们这个例子中就是DEPTNO),所以完全可以在子表中使用这个键,而不必使用一个系统生成的键。
q 这会在父表上增加另一个惟一约束(相应地带来不必要的开销),而父表中通常已经有一个惟一约束。
q 如果不使用NESTED_TABLE_GET_REFS(这个方法未得到公开支持),.如果是查询,可以通过消除嵌套来访问嵌套表,但是如果是大批量更新,则无法简单地消除嵌套。
不 过作为一个编程构造,我确实大量使用了嵌套表,并把嵌套表用于视图中。我认为这才是嵌套表应有的位置。作为一个存储机制,我更倾向于我自己创建父/子表。 创建了父/子表之后,实际上,我们可以再创建一个视图,使之看上去就好像我们有一个真正的嵌套表一样。也就是说,这样做可以得到嵌套表构造的所有好处,而 不会引入嵌套表的开销。
如果你确实把嵌套表用作一个存储机制,一定要保证将嵌套表建立为一个IOT,以避免NESTED_TABLE_ID上索引的开销以及嵌套表本身的开销。如果没有使用IOT,则要确保在嵌套表的NESTED_TABLE_ID 列上创建一个索引,来避免为查找子行而执行全表扫描。