一、概念介绍
table Cluster 是一组共享公共列并在相同块中存储相关数据的表。当使用 table cluster 时,单个数据块可以包含来自多个表的行。例如,一个块可以存储来自 employees 和 departments 表的行,而不是只存储来自单个表的行。
cluster key 是 table cluster 共有的一列或多列。例如, employees 和 departments 表共享 department_id 列。在创建 table cluster 和创建添加到 table cluster 的每个表时,指定 cluster key 。
cluster key value 是特定行集的 cluster key 列的值。所有包含相同 cluster key value 的数据 ( 如 department_id=20) 都被物理地存储在一起。每个 cluster key value 只在 Cluster table 和 cluster index 中存储一次,不管不同表中有多少行包含该值。
例如,
假设一位人力资源经理有两个文件柜 :
一个存储员工文件夹,另一个存储部门文件夹。
用户经常要求查询特定部门的所有员工的文件。
为了使检索更容易,管理员将所有的文件夹重新排列。
她把文件夹按部门编号分开。
因此,所有 deptid=20 的员工文件夹和部门 20 本身的文件夹都在一个盒子里 ;
部门 100 的员工文件夹和部门 100 的文件夹位于不同的盒子中,依此类推。
当主要查询表 ( 但不修改 ) 并且表中的记录经常一起 select 或 join 时,可以考虑使用 table cluster 。由于 table cluster 将不同表的相关行存储在相同的数据块中,因此与非集群表相比,正确使用表集群具有以下优点:
l 对于集群表的连接,减少了磁盘 I/O 。
l 提高了对集群表的连接的访问时间。
l 存储相关表和索引数据所需的存储空间更少,因为不会为每一行重复存储集群键值。
通常,在以下情况下不适合使用聚类表 :
l 这些表经常 update 。
l 这些表经常需要 full table scan 。
l 这些表需要 truncate 。
二、Index cluster
Index cluster 是使用索引来定位数据的 table cluster 。 cluster index 是集群键上的 B-tree 索引。必须先创建 cluster index ,然后才能将数据行插入到 table cluster 中。
假设您使用集群键 department_id 创建了集群 employees_departments_cluster ,如示例 2-8 所示。因为没有指定 HASHKEYS 子句,所以这个集群是一个索引集群。然后,在这个集群键上创建一个名为 idx_emp_dept_cluster 的索引。
Example 2-8 Indexed Cluster
CREATE CLUSTER employees_departments_cluster
(department_id NUMBER(4))
SIZE 512;
CREATE INDEX idx_emp_dept_cluster ON CLUSTER employees_departments_cluster;
然后在集群中创建 employees 和 departments 表,指定 department_id 列作为集群键,如下所示 ( 省略号表示列定义所在的位置 ):
CREATE TABLE employees ( ... )
CLUSTER employees_departments_cluster (department_id);
CREATE TABLE departments ( ... )
CLUSTER employees_departments_cluster (department_id);
最后,向 employees 和 departments 表添加行。 数据库在物理上使用 相同数据块 存储 employees 和 departments 表的 每个部门的所有行 。 数据库将这些行存储在堆中,并使用索引来定位它们。
图 2-6 显示了 employees_departments_cluster 表集群,其中包含员工和部门。 数据库分别将部门 20 的员工行存储在一起,将部门 110 的员工的行存储在一起,以此类推。 如果表不是集群的,则数据库不确保将相关的行存储在一起。
B-tree 集群索引将集群键值与包含数据的块的数据库块地址 (DBA) 关联起来。例如, key 20 的索引项显示了包含 department 20 员工数据的 block 的地址 :
20,AADAAAA9d
集群索引是单独管理的,就像非集群表上的索引一样,可以存在于与表集群不同的表空间中。
三、Hash Cluster
哈希集群与索引集群类似,不同之处是索引键被哈希函数替换。不存在单独的集群索引。在哈希集群中,数据是索引。
对于索引表或索引集群, Oracle 数据库使用存储在单独索引中的键值来定位表行。要在索引表或表集群中查找或存储一行,数据库必须执行至少两个 I/O:
l 在索引中查找或存储键值的一个或多个 I/O
l 另一个 I/O 来读取或写入表或表集群中的行
要在 hash cluster 中查找或存储一行, Oracle 数据库将 hash 函数应用于该行的集群键值。产生的 hash 值对应于集群中的一个数据块,数据库根据执行的 sql 语句对这个数据块进行读写。
hash 是一种可选的存储表数据的方法,以提高数据检索的性能。 当满足以下条件时,哈希集群提高性能:
l 查询表的频率比修改表的频率高得多。
l 哈希键列经常使用相等条件进行查询,例如, department_id=20 。 对于这样的查询,集群键值是散列的,哈希键值直接指向存储行的磁盘区域。
l 合理地证估散列键的数量和每个键值存储的数据的大小。
3.1 Hash Cluster Creation
集群键与索引集群的键一样,是由集群中的表共享的单个列或组合键。
哈希键值是插入到
cluster
键列中的实际值或可能值。
例如,如果集群键是
department_id
,那么散列键值可以是
10
、
20
、
30
等等。
每个桶都有一个惟一的数字 ID ,称为散列值。 每个散列值映射到存储与散列键值对应的行 ( 部门 10 、 20 、 30 ,等等 ) 的数据库块地址。
集群的散列值的数量取决于散列键。 在例 2-9 中,可能存在的部门数为 100 ,因此 HASHKEYS 被设置为 100 。
Example 2-9 Hash Cluster
CREATE CLUSTER employees_departments_cluster
(department_id NUMBER(4))
SIZE 8192 HASHKEYS 100;
在创建 employees_departments_cluster 之后,可以在集群中创建 employees 和 departments 表。然后可以将数据加载到散列集群中,就像在示例 2-8 中描述的索引集群中一样。
3.2 Hash Cluster Queries
数据库,而不是用户,决定如何哈希用户输入的键值。例如,假设用户经常执行以下查询,为 p_id 输入不同的部门 ID 号 :
SELECT *
FROM employees
WHERE department_id = :p_id;
SELECT *
FROM departments
WHERE department_id = :p_id;
SELECT *
FROM employees e, departments d
WHERE e.department_id = d.department_id
AND d.department_id = :p_id;
如果用户查询 department_id=20 中的雇员,那么数据库可能会将该值散列到 bucket 77 。如果用户查询 department_id=10 中的员工,那么数据库可能会将该值散列到 bucket 15 。数据库使用内部生成的散列值来定位包含所请求部门的雇员行的块。
图 2-7 将散列集群段描述为水平的块行。如图所示,查询可以在单个 I/O 中检索数据。
散列集群的一个限制是无法对非索引的集群键进行范围扫描。假设在例 2-9 中创建的散列集群没有单独的索引。对于 id 在 20 到 100 之间的部门的查询不能使用散列算法,因为它不能散列 20 到 100 之间的所有可能值。因为不存在索引,所以数据库必须执行完整扫描。
3.3 Hash Cluster Variations
single-table hash cluster 是哈希集群的优化版本,一次只支持一个表。哈希键和行之间存在一对一的映射。当用户需要通过主键快速访问表时,单表散列集群可能是有益的。例如,用户经常通过 employee_id 在 employees 表中查找雇员记录。
sorted hash cluster 存储与哈希函数的每个值对应的行,这样数据库就可以有效地按排序顺序返回它们。数据库在内部执行优化排序。对于总是按排序顺序使用数据的应用程序,这种技术意味着可以更快地检索数据。例如,应用程序可能总是对 orders 表的 order_date 列进行排序。
3.4 Hash Cluster Storage
Oracle 数据库为散列集群分配空间的方式与索引集群不同。在例 2-9 中, HASHKEYS 指定可能存在的部门数量,而 SIZE 指定与每个部门关联的数据的大小。数据库根据以下公式计算存储空间值 :
HASHKEYS * SIZE / database_block_size
因此,如果示例 2-9 中的块大小为 4096 字节,那么数据库至少会向散列集群分配 200 个块。
Oracle 数据库不限制可以插入到集群中的散列键值的数量。例如,即使 HASHKEYS 是 100 ,也不能阻止您在 departments 表中插入 200 个惟一的部门。但是,当哈希值的数量超过哈希键的数量时,哈希集群检索的效率就会降低。
为了说明检索问题,假设图 2-7 中的 block 100 完全包含了 department 20 的行。用户使用 department_id 43 将新部门插入到部门表中。 department 的数量超过了 HASHKEYS 值,因此数据库将 department_id 43 散列为散列值 77 ,这与 department_id 20 使用的散列值相同。将多个输入值哈希到同一个输出值称为哈希冲突。
数据库将块 100 链接到一个新的溢出块,比如块 200 ,并将插入的行存储在新块中。 block 100 和 block 200 现在都可以为其中任何一个部门存储数据。 如图 2-8 所示,一个部门 20 或 43 的查询现在需要两个 I/O 来检索数据 :block 100 及其相关的 block 200 。 您可以通过使用不同的 HASHKEYS 值重新创建集群来解决这个问题。
From 《 Oracle® Database Concepts 11 g Release 2 (11.2) 》 . Overview of Table Clusters