Oracle 支持两种类型的聚簇:索引聚簇和哈希聚簇
使用索引聚簇指南
一:首先介绍一下索引聚簇表的工作原理:
聚簇:如果一组表有一些共同的列,则将这样一组表存储在相同的数据库块中;聚簇还表示把相关的数据存储在同一个块上。利用聚簇,一个块可能包含多个表的数据。概念上就是如果两个或多个表经常做链接操作,那么可以把需要的数据预先存储在一起。聚簇还可以用于单个表,可以按某个列将数据分组存储。
更加简单的说,比如说,EMP表和DEPT表,这两个表存储在不同的segment中,甚至有可能存储在不同的TABLESPACE中,因此,他们的数据一定不会在同一个BLOCK里。而我们有会经常对这两个表做关联查询,比如说:select * from emp,dept where emp.deptno = dept.deptno .仔细想想,查询主要是对BLOCK的操作,查询的BLOCK越多,系统IO就消耗越大。如果我把这两个表的数据聚集在少量的BLOCK里,查询效率一定会提高不少。
比如我现在将值deptno=10的所有员工抽取出来,并且把对应的部门信息也存储在这个BLOCK里(如果存不下了,可以为原来的块串联另外的块)。这就是索引聚簇表的工作原理。
二:创建过程。
索引聚簇表是基于一个索引聚簇(index cluster)创建的。里面记录的是各个聚簇键。
聚簇键和我们用得做多的索引键不一样,索引键指向的是一行数据,聚簇键指向的是一个ORACLE BLOCK。我们可以先通过以下命令创建一个索引簇。
SQL> conn scott/tiger
已连接。
SQL> desc dept
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
DEPTNO NOT NULL NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)
SQL> create cluster emp_dept_cluster
2 ( deptno number(2) )
3 size 1024
4 /
簇已创建。
这个名字可以用户定义,不一定叫deptno,数据类型必须和需要使用这个聚簇的数据类型一致NUMBER(2)。在这里最关键的一个参数是size。这个选项原来告诉Oracle:我们希望与每个聚簇键值关联大约1024字节的数据(1024对于一般的表一条数据没问题),Oracle会在用这个数据库块上设置来计算每个块最 多能放下多少个聚簇键。假设块大小为8KB,Oracle会在每个数据库块上放上最多7个聚簇键,也就是说,对应部门10、20、30、40、50、60和70的数据会放在一个块上,一旦插入部门80,就会使用一个新块。存放的数据是和插入顺序相关的。
因 此,SIZE测试控制着每块上聚簇键的最大个数。这是对聚簇空间利用率影响最大的因素。如果把这个SIZE设置得太高,那么每个块上的键就会很少(单位BLOCK可以存的聚簇键就少了),我们会不必要地使用更多的空间。如果设置得太低,又会导致数据过分串链(一个聚簇键不够存放一条数据),这又与聚簇本来的目的不符,因为聚簇原本是为了把所有相关数据都存储在一个块上。
向聚簇中放数据之前,需要先对聚簇建立索引。可以现在就在聚簇中创建表,但是由于我们想同时创建和填充表,而有数据之前必须有一个聚簇索引,所以我们先来建立聚簇索引。
聚簇索引的任务是拿到一个聚簇键值,然后返回包含这个键的块的块地址。实际上这是一个主键,其中每个聚簇键值指向 聚簇本身中的一个块。因此,我们请求部门10的数据时,Oracle会读取聚簇键,确定相应的块地址,然后读取数据。聚簇键索引如下创建:
SQL> create index emp_dept_cluster_idx
2 on cluster emp_dept_cluster
3 /
索引已创建。
现在可以创建表了:
SQL> conn segment_study/liugao
已连接。
SQL> create table dept
2 ( deptno number(2) primary key, 3 dname varchar2(14),
4 loc varchar2(13)
5 )
6 cluster emp_dept_cluster(deptno)
7 /
表已创建。
SQL> create table emp
2 ( empno number primary key, 3 ename varchar2(10), 4 job varchar2(9), 5 mgr number, 6 hiredate date, 7 sal number, 8 comm number,
9 deptno number(2) constraint emp_fk references dept(deptno)
10 )
11 cluster emp_dept_cluster(deptno)
12 /
表已创建。
我们可以通过一下SQL语句查看创建:
SQL> select cluster_name, table_name
2 from user_tables
3 where cluster_name is not null
4 order by 1;
CLUSTER_NAME TABLE_NAME
------------------------------ -----------------------------
EMP_DEPT_CLUSTER DEPT
EMP_DEPT_CLUSTER EMP
现在,聚簇,聚簇索引,聚簇索引表都已经建立完成。
三:加载数据。
向聚簇索引表中加载数据是个很讲究的事情,处理方法不对,会使得聚簇的功能发挥不完全,降低查询性能。
方法1:
首先,我增加一个很大的列char(1000),加这个列是为了让EMP行远远大于现在的大小。使得一个1024的聚簇无法存储一行记录。不能加varchar2(1000),因为ORACLE对varchar2存储的原则是能省就省,如果数据数据不到1000,不会分配1000的空间的。char则是有多少用多少。呵呵。
SQL> begin
2 for x in ( select * from scott.dept )
3 loop
4 insert into dept
5 values ( x.deptno, x.dname, x.loc );
6 insert into emp
7 select *
8 from scott.emp 9 where deptno = x.deptno;
10 end loop;
11 end;
12 /
begin
*
第1行出现错误:
ORA-02032:聚簇表无法在簇索引建立之前使用
ORA-06512:在line 4
SQL> create index emp_dept_cluster_idx
2 on cluster emp_dept_cluster
3 ;
索引已创建。
SQL> alter table emp disable constraint emp_fk;
表已更改。
SQL> truncate cluster emp_dept_cluster;
簇已截断。
SQL> alter table emp enable constraint emp_fk;
表已更改。
SQL> alter table emp add data char(1000);
表已更改。
上面的执行错误说明聚簇表无法在簇索引建立之前使用。
首先我们通过先加载emp表,后加载dept表的方式。
SQL> insert into dept
2 select * from scott.dept;已创建4行。
SQL> insert into emp
2 select emp.*, '*' from scott.emp;已创建14行。
然后做一个查询,通过dbms_rowid.rowid_block_number可以查看此数据所在的BLOCK ID,如果dept和emp存储的行数据不是一个BLOCK ID ,则标记一个'*'.查询结果如下:
SQL> select dept_blk, emp_blk, 2 case when dept_blk <> emp_blk then '*' end flag,
3 deptno
4 from (
5 select dbms_rowid.rowid_block_number(dept.rowid) dept_blk, 6 dbms_rowid.rowid_block_number(emp.rowid) emp_blk, 7 dept.deptno 8 from emp, dept 9 where emp.deptno = dept.deptno
10 )
11 order by deptno
12 /
DEPT_BLK EMP_BLK F DEPTNO
---------- ---------- - ----------
85 86 * 10
85 86 * 10
85 87 * 10
85 85 20
85 87 * 20
85 86 * 20
85 85 20
85 86 * 20
85 85 30
85 86 * 30
85 85 30
DEPT_BLK EMP_BLK F DEPTNO
---------- ---------- - ----------
85 86 * 30
85 85 30
85 85 30
已选择14行。
我们发现,通过先插入emp数据,再插入dept数据,导致大部分的emp和dept的数据都不在一个block上,这不是我们使用聚簇索引的目的。
方法二:
先处理一下刚才插入的数据:
SQL> truncate cluster emp_dept_cluster;
truncate cluster emp_dept_cluster
*
第1行出现错误:
ORA-02266:表中的唯一/主键被启用的外键引用
SQL> alter table emp disable constraint emp_fk;
表已更改。
SQL> truncate cluster emp_dept_cluster;
簇已截断。
SQL> alter table emp enable constraint emp_fk;
表已更改。
然后使用以下的方式插入数据:
SQL> begin
2 for x in ( select * from scott.dept )
3 loop
4 insert into dept
5 values ( x.deptno, x.dname, x.loc );
6 insert into emp
7 select emp.*, 'x' 8 from scott.emp 9 where deptno = x.deptno;
10 end loop;
11 end;
12 /
PL/SQL 过程已成功完成。
执行上面统一的SQL。
SQL> select dept_blk, emp_blk, 2 case when dept_blk <> emp_blk then '*' end flag,
3 deptno
4 from (
5 select dbms_rowid.rowid_block_number(dept.rowid) dept_blk, 6 dbms_rowid.rowid_block_number(emp.rowid) emp_blk, 7 dept.deptno 8 from emp, dept 9 where emp.deptno = dept.deptno
10 )
11 order by deptno
12 /
DEPT_BLK EMP_BLK F DEPTNO
---------- ---------- - ----------
85 85 10
85 85 10
85 85 10
85 85 20
85 85 20
85 85 20
85 86 * 20
85 86 * 20
86 86 30
86 86 30
86 86 30
DEPT_BLK EMP_BLK F DEPTNO
---------- ---------- - ----------
86 86 30
86 87 * 30
86 87 * 30
已选择14行。
咱们发现,大部分的数据都在同一个块中。原来这才是想聚簇表里添加数据的最佳方法。
为什么会有这样的差别呢??
当我们通过第一种方法时,有一个问题,由于dept表的行在聚簇中占用空间很小,但是剩余的空间确不能存一条dept的数据(应为我们添加了char(1000)了)。这样就会在那些聚簇 键块上导致过度的串链。Oracle会把包含这些信息的一组块串链或链接起来。如果同时加载对应一个给定聚簇键的所有数据,就能尽可能紧地塞满块,等空间 用完时再开始一个新块。
四:什么时候不应该使用聚簇?
1) 如果预料到聚簇中的表会大量修改:必须知道,索引聚簇会对DML的性能产生某种负面影响(特别是INSERT语句)。管理聚簇中的数据需要做更多的工作。
2) 如果需要对聚簇中的表执行全表扫描:不只是必须对你的表中的数据执行全面扫描,还必须对(可能的)多个表中的数据进行全面扫描。由于需要扫描更多的数据,所以全表扫描耗时更久。
3) 如果你认为需要频繁地TRUNCATE和加载表:聚簇中的表不能截除。这是显然的,因为聚簇在一个块上存储了多个表,必须删除聚簇表中的行。
因此,如果数据主要用于读(这并不表示“从来不写”;聚簇表完全可以修改),而且要通过索引来读(可以是聚簇键索引,也可以是聚簇表上的其他索引),另外会频繁地把这些信息联结在一起,此时聚簇就很适合。
补充关于需要使用聚簇表的情况:
l 考虑对经常在连接语句中访问的表建立聚簇。
l 如果表只是偶尔被连接或者它们的公共列经常被修改,则不要聚簇表。(修改记录的聚簇键值比在非聚簇的表中修改此值要花费更多的时间,因为Oracle 必须将修改的记录移植到其他的块中以维护聚簇)。
l 如果经常需要在一个表上进行完全搜索,则不要聚簇这个表(对一个聚簇表进行完全搜索比在非聚簇表上进行完全搜索的时间长,Oracle 可能要读更多的块,因为表是被一起存储的。)
l 如果经常从一个父表和相应的子表中查询记录,则考虑给1 对多(1:* )关系创建聚簇表。(子表记录存储在与父表记录相同的数据块中,因此当检索它们时可以同时在内存中,因此需要Oracle 完成较少的I/O )。
l 如果经常查询同一个父表中的多个子记录,则考虑单独将子表聚簇。(这样提高了从相同的父表查询子表记录的性能,而且也没有降低对父表进行完全搜索的性能)。
l 如果从所有有相同聚簇键值的表查询的数据超过一个或两个Oracle 块,则不要聚簇表。(要访问在一个聚簇表中的记录,Oracle 读取所有包含那个记录值的全部数据块,如果记录占据了多个数据块,则访问一个记录需要读的次数比一个非聚簇的表中访问相同的记录读的次数要多)。
使用哈希聚簇指南
l 当经常使用有相同列的包含相等条件的查询子句访问表时,考虑使用哈希聚簇来存储表。使用这些列作为聚簇键。
l 如果可以确定存放具有给定聚簇键值的所有记录所需的空间(包括现在的和将来的),则将此表以哈希聚簇存储。
l 如果空间不够,并且不能为将要插入的新记录分配额外的空间,那么不要使用哈希聚簇。
l 如果偶尔创建一个新的、很大的哈希聚簇来保存这样的表是不切实际的,那么不要用哈希聚簇存储经常增长的表。
l 如果经常需要进行全表搜索,并且必须要为表的预期增长中的哈希聚簇分配足够的空间,则不要将此表以哈希聚簇存储。(这样的完全检索必须要读分配给哈希聚簇的全部块,即使有些块可能只包含很少的记录。单独地存储表将减少由完全的表检索读取的块的数量。)
l 如果你的应用程序经常修改聚簇键的值,则不要将表以哈希聚簇方式存储。
l 不管这个表是否经常与其他表连接,只要进行哈希对于基于以前的指南的表是合适的,那么在哈希聚簇中存储一个表可能是有用的。
http://blog.sina.com.cn/s/blog_6bd7d94301014kji.html
相关推荐
### Oracle中聚簇表的使用 #### 聚簇表的概念 在Oracle数据库中,聚簇表(Cluster Table)是一种特殊的数据存储结构,它允许多个表通过共享某些相同的列值来存储在同一个数据块内。这种特性使得相关联的数据能够在...
大家通常oracle中的cluster的理解是不准确的,经常和sql server中的cluster index混淆。Cluster是存储一组table的一种方法,这些table共享同一数据块中的某些相同column,并把不同table在这一共享column上值相同的...
聚簇管理是Oracle数据库管理系统的重要组件,用于管理聚簇的创建、修改、删除等操作。通过dba_clusters视图,可以查询聚簇的基本信息,包括聚簇名称、聚簇类型、创建日期等信息。 快照管理 快照是Oracle数据库中的...
将Excel数据导入Oracle通常需要先将数据转换为CSV格式,然后使用SQL*Loader或外部表来加载数据。 3. **设置时间间隔型数据**: 在Oracle 9i中,时间间隔类型(INTERVAL)用于存储时间间隔,如年、月、日、小时等。...
通过查询特定的系统表,数据库管理员(DBA)或开发人员能够获取关于用户、表空间、数据库对象、表、索引、序列、视图、聚簇以及快照的详细信息,从而进行有效的数据库管理和优化工作。以下是对给定文件中的Oracle...
1. **聚簇信息查询**: - `SELECT * FROM dba_clusters;`:列出所有聚簇。 #### 十、快照管理 1. **快照信息查询**: - `SELECT * FROM dba_snapshots;`:列出所有快照。 - 快照通常存在于专门的表空间中。 ####...
8. 聚簇管理:Oracle 系统表大全中包含了聚簇管理相关的信息,例如聚簇列表、聚簇类型、聚簇所有者等。通过查询 dba_clusters 表,可以获取所有聚簇的信息。例如,select * from dba_clusters; 可以获取所有聚簇的...
聚簇是 Oracle 数据库中的一个逻辑结构,用于存储多个表的数据。Oracle 提供了多种方式来管理聚簇,包括创建聚簇、删除聚簇、修改聚簇属性等。 在 Oracle 中,可以使用以下语句来查询聚簇信息: ```sql select * ...
聚簇索引是数据库表中的一个关键概念,尤其是在关系型数据库系统中,如MySQL、SQL Server、Oracle等。本篇文章将深入探讨更新数据时自动维护的聚簇索引的本质及其作用。 首先,我们来理解什么是聚簇索引。聚簇索引...
本文件主要探讨了如何通过表的设计来提升Oracle数据库的性能,主要包括堆表、索引组织表和聚簇表三种表结构。 1. **堆表**: - 堆表是最基本的表类型,数据以随机的方式存储,没有特定的顺序。这种存储方式的优点...
除了常规的簇,还有一种散列聚簇表,它使用散列函数而非索引来定位行。创建散列簇的例子: ```sql create cluster my_clu_two(empno number(10) ) pctused 70 pctfree 10 tablespace users hash is empno hashkeys ...
表空间可以包含各种类型的数据对象,如表、索引、聚簇等。因此,误删除表空间可能会导致数据丢失,对业务运行造成严重影响。 ### 误删除表空间的恢复前提条件 文章中提到的恢复被删除的表空间需要满足两个主要条件...
有序散列聚簇表是Oracle 10g引入的新特性,它结合了散列聚簇表和索引组织表的特点,行按照某个键值散列,并保持一定的有序性。这种结构适用于那些需要按先进先出原则处理数据的场景,如订单系统中的订单处理。 ### ...
聚簇索引由于与数据存储紧密关联,只有一个表可以拥有一个聚簇索引,通常选择主键作为聚簇索引的列,因为主键的唯一性确保了索引的高效性。聚簇索引对于范围查询和排序操作特别有利,因为数据按照索引顺序存储,可以...
- **`dba_clusters`**:显示数据库中所有聚簇的信息。 - **示例命令**: ```sql SELECT * FROM dba_clusters; ``` ##### 9. 快照管理 - **`dba_snapshots`**:列出所有快照信息。 - **示例命令**: ```sql ...
oracle中有如下几种类型的表:1、堆组织表(heap organized tables):常用的表类型,以堆的方式管理,当增加数据时,将使用段中第一个适合数据大小的...4、散列聚簇表:和聚簇表相似,但是不是用B*Tree索引聚簇码定位数
- **散列聚簇表**:类似聚簇表,但使用散列算法定位数据,适合通过码等式读取数据的情况。 - **嵌套表**:存储在单个行内,允许复杂数据结构,如数组或集合。 - **临时表**:用于临时存储过程中的数据,会话结束...
Oracle使用自平衡的B树结构存储索引键值,每个索引条目指向表中的一个数据块。 2. **位图索引(Bitmap Index)** 位图索引主要用于低基数(非唯一或重复值多)的列,将每个值用一个位来表示,节省空间,适合在并集...
- **表大小**:随着表中数据量的增加,聚簇因子可能会相应增加。这是因为随着数据量的增长,索引记录与数据行之间的空间分布变得不那么集中。 - **索引更新频率**:频繁的插入、删除操作会导致数据行重新排列,进而...
对于索引,SQL Server支持每表1个聚簇索引和最多249个非聚簇索引,而Oracle允许每个表有1个聚簇索引(对于索引组织表)以及无限数量的非聚簇索引。聚簇索引在决定数据物理顺序方面起关键作用,非聚簇索引则独立于...