《Oracle编程艺术》学习笔记(26)-索引聚簇表

本文详细介绍了Oracle中的索引聚簇表,包括创建步骤、存储原理及适用场景。通过实例展示了如何创建和使用聚簇,指出其优势在于提高读取效率,尤其适合数据读取频繁且相关表一起使用的场景。然而,聚簇表不适合频繁修改、全表扫描、需要TRUNCATE和加载的表,以及无法进行分区操作的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

聚簇(cluster)是指:如果一组表有一些共同的列,则将这样一组表存储在相同的数据库块中;聚簇还表示把相关的数据存储在同一个块上。
聚簇并不是有序地存储数据(这是IOT的工作),它是按每个键以聚簇方式存储数据,但数据存储在堆中。利用聚簇,一个块可能包含多个表的数据。聚簇也可以用于单个表,可以按某个列将数据分组存储。
SQL Server 中的聚簇索引(clustered index)则要求行按索引键有序的方式存储,这类似于前面所述的IOT。

例如,有部门和员工2张表,将部门号作为聚簇列,建立聚簇表。这样部门号10的部门数据和包括的所有员工数据都存储在同一个块上,如果放不下,则串链其他块。
但是部门在磁盘上的存储并不是有序的,部门100可能挨在部门1旁边,而与部门101和99离得很远。

创建索引聚簇表(index clustered table)的步骤:
1)创建聚簇

create cluster emp_dep_cluster (depno number(2)) size 2048;

SIZE选项告诉Oracle与每个聚簇键值关联大约2048字节的数据,Oracle会使用这个参数来计算每个块最多能放下多少个聚簇键。假设块大小为8KB,Oracle会在每个数据库块上放上最多3个聚簇键。
对于聚簇来说,SIZE是最重要的参数,这是对聚簇空间利用率影响最大的因素。如果把这个SIZE设置得太高,那么每个块上的键就会很少,会不必要地使用更多的空间。如果设置得太低,又会导致数据过分串链。
对象的存储定义参数(PCTFREE、PCTUSED、INITRANS等)与 CLUSTER相关,而不是与表相关。因为聚簇中会有多个表,而且它们在同一个块上。

2)创建聚簇键索引

create index emp_dep_cluster_idx on cluster emp_dep_cluster;

也可以在聚簇中创建完表格后再创建,但是必须在插入数据前创建,否则会得到下述错误。
ORA-02032: clustered tables cannot be used before the cluster index is built
聚簇索引就像是一个常规的索引,使用和常规同样的的存储参数,也可以存储在另一个表空间中,也可以在多列上建立。
注意,CREATE INDEX语句中,并没有指定列的一个列表,索引列可以由CLUSTER定义本身得出。

3)创建表格

create table department (
  depno number(2) primary key, depname varchar2(20))
  cluster emp_dep_cluster(depno);

create table employee (
  empno number primary key, empname varchar2(20), 
  depno number(2) references department(depno))
  cluster emp_dep_cluster(depno);


需要使用CLUSTER关键字来指定基表的哪个列会映射到聚簇本身的聚簇键。
聚簇中的表使用创建聚簇时生成的聚簇段,不会有诸如TABLESPACE、PCTFREE等段属性。

在表格中插入一些数据,然后观察在磁盘上的存放。

tony@ORA11GR2> select rowid, dbms_rowid.rowid_block_number(rowid) block, depno from department;

ROWID                   BLOCK      DEPNO
------------------ ---------- ----------
AAASIEAAEAAADN0AAA      13172         10
AAASIEAAEAAADN0AAB      13172         20
AAASIEAAEAAADN0AAC      13172         30
AAASIEAAEAAADN1AAA      13173         40

tony@ORA11GR2> select rowid, dbms_rowid.rowid_block_number(rowid) block, empno, depno from employee;

ROWID                   BLOCK      EMPNO      DEPNO
------------------ ---------- ---------- ----------
AAASIEAAEAAADN0AAA      13172       7369         20
AAASIEAAEAAADN0AAB      13172       7566         20
AAASIEAAEAAADN0AAC      13172       7654         30
AAASIEAAEAAADN0AAD      13172       7698         30
AAASIEAAEAAADN0AAE      13172       7782         10
AAASIEAAEAAADN0AAF      13172       7788         20
AAASIEAAEAAADN0AAG      13172       7839         10
AAASIEAAEAAADN0AAH      13172       7844         30
AAASIEAAEAAADN0AAI      13172       7876         20
AAASIEAAEAAADN0AAJ      13172       7902         20
AAASIEAAEAAADN0AAK      13172       7934         10
AAASIEAAEAAADN1AAA      13173       7499         40
AAASIEAAEAAADN1AAB      13173       7521         40
AAASIEAAEAAADN1AAC      13173       7900         40

tony@ORA11GR2> show parameter block_size

NAME                                 TYPE                   VALUE
------------------------------------ ---------------------- ------------------------------
db_block_size                        integer                8192


可以看到:
1)由于我们设置了聚簇的SIZE参数为2048,块大小为8K,所以1个块上最多放3个唯一的聚簇键。因此DEPNO为40的数据放到了另外1个块上。
2)DEPARTMENT和EMPLOYEE中的ROWID有重复。说明ROWID只是在表中唯一。

什么时候适合是用索引聚簇表:
· 数据主要用于读(这并不表示“从来不写”;聚簇表完全可以修改),而且要通过索引来读(可以是聚簇键索引,也可以是聚簇表上的其他索引)
· 需要频繁地把逻辑上相关而且总是一起使用的表信息联结在一起

Oracle数据字典就大量使用了聚簇表。例如
select cluster_name, table_name from dba_tables where cluster_name='C_OBJ#';
C_OBJ#聚簇中存储的主要是与列相关的信息,所以关于表或索引列集的所有信息都物理地存储在同一个块上。Oracle解析一个查询时,它希望访问所引用的表中所有列的数据。如果这些数据都在一个块上,通常就能很容易地得到。

什么时候不适合使用聚簇表:
· 如果预料到聚簇中的表会大量修改。索引聚簇会对DML的性能产生某种负面影响。
· 如果需要对聚簇中的某个表执行全表扫描。全表扫描不只是读取了需要的某个表中的数据,还读取了其它的多个表中的数据,全表扫描耗时更久。
· 如果需要频繁地TRUNCATE和加载表。聚簇中的表不能截除,因为聚簇在一个块上存储了多个表,必须删除聚簇表中的行。
· 如果需要对表进行分区。聚簇中的表不能被分区。聚簇本身也不能被分区。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值