索引聚簇表ICT测试(Index Cluster Table)

ICT(Index Cluster Table)其实是很好用的,按索引顺序排列数据,简单测试了一下.

scott@PRIMARY> create cluster heap_no_cluster 
  2  (empno number)
  3  size 500
  4  /

簇已创建。

scott@PRIMARY> desc heap_no;
 名称                                                  是否为空? 类型
 ----------------------------------------------------- -------- ----------------
--------------------
 EMPNO                                                          NUMBER
 ENAME                                                          NUMBER

scott@PRIMARY> create table heapno
  2  (empno number primary key,
  3  ename number)
  4  cluster heap_no_cluster(empno)
  5  /

表已创建。

scott@PRIMARY> desc table heap_addresses
用法: DESCRIBE [schema.]object[@db_link]
scott@PRIMARY>
scott@PRIMARY> desc heap_addresses
 名称                                                  是否为空? 类型
 ----------------------------------------------------- -------- ----------------
--------------------
 EMPNO                                                 NOT NULL NUMBER
 ADDR_TYPE                                             NOT NULL VARCHAR2(10)
 STREET                                                         VARCHAR2(20)
 CITY                                                           VARCHAR2(20)
 STATE                                                          VARCHAR2(2)
 ZIP                                                            NUMBER
 TESTNO                                                         NUMBER

scott@PRIMARY> create table heap
  2  (empno number references heapno(empno)
  3  addr_type varchar2(10),
  4  street varchar2(20),
  5  city varchar2(20),
  6  state varchar2(2),
  7  zip number
  8  ,testno number)
  9  cluster heap_no_cluster(empno)
 10  /
addr_type varchar2(10),
*
第 3 行出现错误:
ORA-00907: missing right parenthesis


scott@PRIMARY> edi
已写入 file afiedt.buf

  1  create table heap
  2  (empno number references heapno(empno),
  3  addr_type varchar2(10),
  4  street varchar2(20),
  5  city varchar2(20),
  6  state varchar2(2),
  7  zip number
  8  ,testno number)
  9* cluster heap_no_cluster(empno)
scott@PRIMARY> /

表已创建。

scott@PRIMARY> edi
已写入 file afiedt.buf

  1  begin
  2  for x in (select * from heap_no)
  3  loop
  4  insert into heapno
  5* values(x.empno,x.ename)
scott@PRIMARY> desc heap_no;
 名称                                                  是否为空? 类型
 ----------------------------------------------------- -------- ----------------
--------------------
 EMPNO                                                          NUMBER
 ENAME                                                          NUMBER

scott@PRIMARY> edit
已写入 file afiedt.buf

  1  begin
  2  for x in (select * from heap_no)
  3  loop
  4  insert into heapno
  5  values(x.empno,x.ename);
  6  insert into heap
  7  select * from heap_addresses
  8  where empno=x.empno;
  9  end loop;
 10* end;
scott@PRIMARY> /
begin
*
第 1 行出现错误:
ORA-02032: clustered tables cannot be used before the cluster index is built
ORA-06512: at line 4


scott@PRIMARY> edi
已写入 file afiedt.buf

  1  begin
  2  for x in (select * from heap_no)
  3  loop
  4  insert into heapno
  5  values(x.empno,x.ename);
  6  insert into heap
  7  select * from heap_addresses
  8  where empno=x.empno;
  9  end loop;
 10* end;
scott@PRIMARY> create index heap_no_cluster_idx on cluster heap_no_cluster;

索引已创建。

scott@PRIMARY> edi
已写入 file afiedt.buf

  1  begin
  2  for x in (select * from heap_no)
  3  loop
  4  insert into heapno
  5  values(x.empno,x.ename);
  6  insert into heap
  7  select * from heap_addresses
  8  where empno=x.empno;
  9  end loop;
 10* end;
scott@PRIMARY> /

PL/SQL 过程已成功完成。

scott@PRIMARY> analyze table heap_no compute statistics;

表已分析。

scott@PRIMARY> analyze table heap compute statistics;

表已分析。

scott@PRIMARY> analyze table heap_no_cluster compute statistics;
analyze table heap_no_cluster compute statistics
              *
第 1 行出现错误:
ORA-00942: table or view does not exist


scott@PRIMARY> analyze cluster heap_no_cluster compute statistics;

簇已分析。

scott@PRIMARY> select a.empno,b.ename
  2  from heap a,heapno b
  3  where a.empno=15238
  4  and a.empno=b.empno
  5
scott@PRIMARY> ecit
SP2-0042: 未知命令 "ecit" - 其余行忽略。
scott@PRIMARY> edi
已写入 file afiedt.buf

  1  select a.empno,b.ename
  2  from heap a,heapno b
  3  where a.empno=15238
  4* and a.empno=b.empno

已经准备好数据,并且分析过表及聚簇了,现在看一下具体的执行计划,首先对聚簇进行查询,再查询普通表.

scott@PRIMARY> set autotrace traceonly;
scott@PRIMARY> edi
已写入 file afiedt.buf

  1  select a.empno,b.ename
  2  from heap a,heapno b
  3  where a.empno=15238
  4* and a.empno=b.empno
scott@PRIMARY> /


执行计划
----------------------------------------------------------
Plan hash value: 2212161699

--------------------------------------------------------------------------------
------------
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)
| Time     |
--------------------------------------------------------------------------------
------------
|   0 | SELECT STATEMENT             |             |     5 |    60 |     3   (0)
| 00:00:01 |
|   1 |  NESTED LOOPS                |             |     5 |    60 |     3   (0)
| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| HEAPNO      |     1 |     8 |     2   (0)
| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | SYS_C005395 |     1 |       |     1   (0)
| 00:00:01 |
|*  4 |   TABLE ACCESS CLUSTER       | HEAP        |     5 |    20 |     1   (0)
| 00:00:01 |
--------------------------------------------------------------------------------
------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("B"."EMPNO"=15238)
   4 - filter("A"."EMPNO"=15238)


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          6  consistent gets
          0  physical reads
          0  redo size
        450  bytes sent via SQL*Net to client
        392  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          5  rows processed

scott@PRIMARY> edi
已写入 file afiedt.buf

  1  select a.empno,b.ename
  2  from heap_addresses a,heap_no b
  3  where a.empno=15238
  4* and a.empno=b.empno
scott@PRIMARY> /


执行计划
----------------------------------------------------------
Plan hash value: 275802435

--------------------------------------------------------------------------------
--
| Id  | Operation          | Name        | Rows  | Bytes | Cost (%CPU)| Time
 |
--------------------------------------------------------------------------------
--
|   0 | SELECT STATEMENT   |             |     5 |    65 |    30   (7)| 00:00:01
 |
|   1 |  NESTED LOOPS      |             |     5 |    65 |    30   (7)| 00:00:01
 |
|*  2 |   TABLE ACCESS FULL| HEAP_NO     |     1 |     8 |    28   (8)| 00:00:01
 |
|*  3 |   INDEX RANGE SCAN | SYS_C005363 |     5 |    25 |     2   (0)| 00:00:01
 |
--------------------------------------------------------------------------------
--

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("B"."EMPNO"=15238)
   3 - access("A"."EMPNO"=15238)


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        109  consistent gets
          0  physical reads
          0  redo size
        450  bytes sent via SQL*Net to client
        392  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          5  rows processed

scott@PRIMARY>

从执行计划上来看,对聚簇的查询产生的COST非常低,且一致性读非常低,还是值得做的措施,对于聚簇表的使用环境网上有很多介绍,这里不再赘述,只是想通过例子来实验一下,得出结论究竟ICT可以做到什么样的优化,要用好ICT最重要的就是充分计算好SIZE的大小.
SIZE该如何计算呢?
很简单,想象一下HEAPNO等于DEPT,HEAP等于EMP,那么表的关系就好理解了,首先analyze一下所有的表,这里最好不要用dbms_stats包,后者不计算行头的3个字节,我们用来计算的数据尽量做的冗余一些.
然后来看它们的行长度:
scott@PRIMARY> edit
已写入 file afiedt.buf

  1  select table_name,avg_row_len from user_tables
  2  where table_name='HEAP'
  3  union
  4  select table_name,avg_row_len from user_tables
  5* where table_name='HEAPNO'
scott@PRIMARY> /

TABLE_NAME                                                   AVG_ROW_LEN
------------------------------------------------------------ -----------
HEAP                                                                  73
HEAPNO                                                                33

scott@PRIMARY> select count(*) from heap where empno=15238;

  COUNT(*)
----------
         5

scott@PRIMARY> select count(*) from heapno where empno=15238;

  COUNT(*)
----------
         1

scott@PRIMARY>
也就是说,1条heapno对应5条heap记录,那么一个聚簇键的大小就应该计算为:(HEAPNO_ROW_LEN)+(HEAP_ROW_LEN)*5=33+73*5=398,我的SIZE设置为500是冗余大小.因为有SIZE设置,所以聚簇在使用时对与记录数量的扩展就显的要差一些,如果聚簇键记录数扩展太块,超过了SIZE值就会溢出存储到另外的块,但这并不是说不能DML,只不过要看这个DML要怎么样来插入,尽量避免过度的块串链,若是父子表组做聚簇的话,那么插入顺序尽量保证先插入1个父表记录然后插入对应的子表记录,尽量不要把父表记录都插入完了再插入子表.

聚簇不仅可以用于父子表中,也可以用于两个单表中,只要有共同的列,看测试:
lcbj@SUPPORT> create cluster t1_t2_cluster
  2  (id number)
  3  size 7000;

簇已创建。

lcbj@SUPPORT> create table t1
  2  (id number primary key,
  3  name varchar2(20))
  4  cluster t1_t2_cluster(id)
  5  /

表已创建。

lcbj@SUPPORT> create table t2
  2  (id number primary key,
  3  address varchar2
  4
lcbj@SUPPORT> drop table t1;

表已删除。

lcbj@SUPPORT> create table t1
  2  (id number,
  3  name varchar2(20))
  4  cluster t1_t2_cluster(id)
  5  /

表已创建。

lcbj@SUPPORT> create table t2
  2  (id number,
  3  addr varchar2(20))
  4  cluster t1_t2_cluster(id)
  5  /

表已创建。

lcbj@SUPPORT> insert into t1 values(1,'x');
insert into t1 values(1,'x')
            *
第 1 行出现错误:
ORA-02032: clustered tables cannot be used before the cluster index is built


lcbj@SUPPORT> create index t1_t2_cluster_idx on cluster t1_t2_cluster;

索引已创建。

lcbj@SUPPORT> insert into t1 values(1,'x');

已创建 1 行。

lcbj@SUPPORT> insert into t1 values(2,'x');

已创建 1 行。

lcbj@SUPPORT> insert into t1 values(3,'x');

已创建 1 行。

lcbj@SUPPORT> insert into t2 values(4,'x');

已创建 1 行。

lcbj@SUPPORT> insert into t2 values(5,'x');

已创建 1 行。

lcbj@SUPPORT> insert into t2 values(6,'x');

已创建 1 行。

lcbj@SUPPORT> commit;

提交完成。

lcbj@SUPPORT>

这时候t1里面有三条记录,分别是1,2,3,根据size的设置,一定是不在同一个块中,t2中的记录是4,5,6,也不在一个块中,验证一下:
lcbj@SUPPORT> select dbms_rowid.rowid_block_number(t1.rowid) t1_blk from t1;

    T1_BLK
----------
    108684
    108687
    108688

lcbj@SUPPORT> select dbms_rowid.rowid_block_number(t2.rowid) t1_blk from t2;

    T1_BLK
----------
    108685
    108686
    108702

lcbj@SUPPORT>
这说明,它们都保存数据在聚簇段了,我们再来看看插入1,2,3的记录到t2以后的情况:
lcbj@SUPPORT> select id,dbms_rowid.rowid_block_number(t2.rowid) t1_blk from t2;

        ID     T1_BLK
---------- ----------
         3     108684
         5     108685
         4     108686
         1     108687
         2     108688
         6     108702

已选择6行。

lcbj@SUPPORT> select id,dbms_rowid.rowid_block_number(t1.rowid) t1_blk from t1;

        ID     T1_BLK
---------- ----------
         3     108684
         1     108687
         2     108688

lcbj@SUPPORT>
可以看到,ID相等的都放在同一个块中,聚簇的管理已经起到作用,所以说不一定父子表才能做聚簇,只要是有相同的列,都可以做聚簇.

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16628454/viewspace-609951/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/16628454/viewspace-609951/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值