本节书摘来自异步社区出版社《Oracle数据库管理与维护实战》一书中的第2章,第2.7节,作者: 何伟娜 , 常建功,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.7 数据分区
Oracle数据库管理与维护实战
巨型表或索引由于太大,在数据库系统会引起类似以下几条的很多问题。
因为表变得非常大,以至于要花费大量的时间对这张表进行管理。
对巨型表进行全表扫描,会花费系统大量的时间和资源。
一个事务要查询这张巨型表,如果由于磁盘错误,读写一个数据块发生错误,整个表就变得不能用。管理员恢复这张表要耗费很长时间。
为减少这类问题的发生,Oracle使用分区表和分区索引。
2.7.1 分区表
Oracle允许将表的存储分离为一些空间较小的存储单元,这些小的存储单元就称为分区。每个表的分区含有相同的数据类型和完整性约束,但每个分区之间可以含有不同的物理属性。例如,Oracle能够在不同的表空间中存储一个表的各个分区,并且每一个分区都可以设置pctfree、pctused等存储参数,分区表与普通表的物理存储如图2-26所示。
表分区有以下优点。
用户能对表分区单独创建、重建索引,能单独装载、备份恢复表分区数据。因为只对指定的表分区进行操作,所以比对整张表进行操作快得多。
表分区能提高查询性能。一般要查询的数据都在一个表分区中,所以不必对全表扫描,而只需对分区扫描。
表分区可以提高对表的并发操作。不同事务可以对同一表的不同分区同时进行操作。
分区表对用户来说是透明的,用户可以像操作一张普通的表一样操作分区表。
2.7.2 分区表的类型
Oracle表有几种分区方法:范围分区(Range Partitioning)、列表分区(List Partitioning)、散列分区(Hash Partitioning)、复合分区(Composite Partitioning)。
1.范围分区
Oracle支持范围分区表,根据表分区键值决定数据存储的分区。表分区键值是一个表字段值或多个字段值的组合(最多16个字段组合),但这些字段不能是LEVEL、ROWID或MLSLABEL等伪列。为防止表分区之间记录迁移,表分区键值不宜修改。为了理解范围分区表,下面我们举一个创建范围分区表的例子。以下是一张销售清单表,以销售日期为分区键值分区。
CREATE TABLE sales
(invoice_no NUMBER,
sale_year INT NOT NULL,
sale_month INT NOT NULL,
sale_day INT NOT NULL)
STORAGE (INITIAL 100K NEXT 50K) LOGGING
PARTITION BY RANGE (sale_year, sale_month, sale_day)
(PARTITION sales_q1 VALUES LESS THAN (1999, 04, 01)
TABLESPACE tsa STORAGE (INITIAL 20K, NEXT 10K),
PARTITION sales_q2 VALUES LESS THAN (1999, 07, 01)
TABLESPACE tsb,
PARTITION sales_q3 VALUES LESS THAN (1999, 10, 01)
TABLESPACE tsc,
PARTITION sales q4 VALUES LESS THAN (2000, 01, 01)
TABLESPACE tsd)
ENABLE ROW MOVEMENT;
2.列表分区
列表分区和范围分区不同,范围分区以分区键值的范围为标准划分分区,而列表分区按照预先给定的一系列离散值进行分区。新数据插入表中时,根据分区键值找到对应分区。以下是建立列表分区的例子。
CREATE TABLE sales_list
(salesman_id NUMBER(5),
salesman_name VARCHAR2(30),
sales_state VARCHAR2(20),
sales_amount NUMBER(10),
sales_date DATE)
PARTITION BY LIST(sales_state)
(
PARTITION sales_west VALUES('California', 'Hawaii'),
PARTITION sales_east VALUES ('New York', 'Virginia', 'Florida'),
PARTITION sales_central VALUES('Texas', 'Illinois'),
PARTITION sales_other VALUES(DEFAULT)
);
如以下一行数据,因为在分区sales_west中有 'Hawaii' ,所以这一行插入sales_west分区中。
(10, 'Jones', 'Hawaii', 100, '05-JAN-2000')
因为列表分区只根据离散值指定分区,所以有很多记录并不对应任何值,列表分区就将这些记录存储在一个默认的分区中。需要注意的是,列表分区只能用一列分区键值,而不能像范围分区一样能定多个分区键值。
3.散列分区
散列分区的分区方法完全不同于范围分区和列表分区。散列分区先通过散列函数对分区键值计算,根据计算结果确定记录存储到哪个分区。散列分区的定义比较简单,使用也比较方便。散列分区适用于以下几种情况:
事先不知道指定的范围内将会有多少数据,此时可以用散列分区。
如果用范围分区,各区之间数据量差异将会很大,并且很难人工干预达到各分区间数据量平衡,此时可以用散列分区。
以下是一个定义散列分区的例子。
CREATE TABLE sales_hash
(salesman_id NUMBER(5),
salesman_name VARCHAR2(30),
sales_amount NUMBER(10),
week_no NUMBER(2))
PARTITION BY HASH(salesman_id)
PARTITIONS 4
STORE IN (ts1, ts2, ts3, ts4);
4.复合分区
复合分区是将范围分区和列表分区或散列分区混合使用的一种分区方法。复合分区在分区上用的是范围分区,而在每个分区上又可以用列表分区法或散列分区分成多个子分区,所以复合分区又分为范围散列分区和范围列表分区两种类型。图2-27是范围列表分区的存储示意图。
图2-27中纵向是根据月份来划分的范围分区,每个范围分区又以列表方式划分为3个子分区。使用复合分区的优点是能吸取多个分区类型的优点。
2.7.3 分区索引
与表一样,索引可以分区,叫作分区索引,每个索引必须有相同的索引列,但可以有不同的存储特性。一个索引的分区键值决定在哪个分区存储索引项。一个索引的分区必须包含一个或多个被索引的列。索引分区的定义和表分区定义类似。不论是分区表还是非分区表,用户都可以给它建立分区索引。
2.7.4 索引的类型
只有当索引本身很大时,分区索引才有必要创建。分区索引的主列选择和普通索引的主列选择一样。分区索引有两种类型:本地索引和全局分区索引。
1.本地索引
如果两个或两个以上的数据库对象有相同的逻辑分区属性,例如两张分区表有相同的分区键值和相同的分区范围,那么它们就是相同的分区。如果一张分区表和分区索引具有相同的逻辑分区属性,那么这两个索引就是具有相同分区的本地索引,如图2-28所示。
创建本地索引比较容易,范围说明和最大索引值可以不指定。分区索引会自动从分区表中获得这些属性。
2.全局索引
用户可以创建一个和分区表不同分区属性的索引,这就是全局分区索引。全局分区索引覆盖了整个表的范围,和表分区没有任何联系,不分区的表也可以创建全局索引。全局索引在OLTP环境下能够提供比本地索引更好的性能。图2-29是全局索引的使用示例。
2.7.5 表分区和分区管理
用户可以对表的每个分区进行单独命名,也可以像操作一张普通表一样对这个命名的表分区进行存取。使用命名表分区能够方便开发人员,并且能减少查询的冗余。虽然开发人员可以像操作表一样操作命名分区,但是表分区毕竟涉及到表的物理存储方式,还是尽量不要轻易使用。Oracle提供了很多操作分区表的方法,这些方法对表调优很有用。
分区表和非分区表可以互相转化。
用户可以在一个已有的表分区后添加新分区。
用户可以分割合并表分区。
用户可以删除表中不含任何记录的分区。
用户可以删除指定的表分区而不删除整个表。