嵌套表

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 列上创建一个索引,来避免为查找子行而执行全表扫描

转载于:https://my.oschina.net/u/1862478/blog/1832927

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值