一 表空间及分区表的概念
表空间:
是一个或多个数据文件的集合,全部的数据对象都存放在指定的表空间中,但主要存放的是表, 因此称做表空间。
分区表:
当表中的数据量不断增大,查询数据的速度就会变慢,应用程序的性能就会降低,这时就应该考虑对表进行分区。表进行分区后,逻辑上表仍然是一张完整的表,只是将表中的数据在物理上存放到多个表空间(物理文件上),这样查询数据时,不至于每次都扫描整张表。
二 表分区的具体做用
Oracle的表分区功能经过改善可管理性、性能和可用性,从而为各式应用程序带来了极大的好处。一般,分区可使某些查询以及维护操做的性能大大提升。此外,分区还能够极大简化常见的管理任务,分区是构建千兆字节数据系统或超高可用性系统的关键工具。
分区功能可以将表、索引或索引组织表进一步细分为段,这些数据库对象的段叫作分区。每一个分区有本身的名称,还能够选择本身的存储特性。从数据库管理员的角度来看,一个分区后的对象具备多个段,这些段既可进行集体管理,也可单独管理,这就使数据库管理员在管理分区后的对象时有至关大的灵活性。可是,从应用程序的角度来看,分区后的表与非分区表彻底相同,使用 SQL DML 命令访问分区后的表时,无需任何修改。
何时使用分区表:
一、表的大小超过2GB。
二、表中包含历史数据,新的数据被增长都新的分区中。
三 表分区的优缺点
表分区有如下优势:
一、改善查询性能:对分区对象的查询能够仅搜索本身关心的分区,提升检索速度。
二、加强可用性:若是表的某个分区出现故障,表在其余分区的数据仍然可用;
三、维护方便:若是表的某个分区出现故障,须要修复数据,只修复该分区便可;
四、均衡I/O:能够把不一样的分区映射到磁盘以平衡I/O,改善整个系统性能。
缺点:
分区表相关:已经存在的表没有方法能够直接转化为分区表。不过 Oracle 提供了在线重定义表的功能。
四 表分区的几种类型及操做方法
4.1 范围分区
范围分区将数据基于范围映射到每个分区,这个范围是你在建立分区时指定的分区键决定的。这种分区方式是最为经常使用的,而且分区键常常采用日期。举个例子:你可能会将销售数据按照月份进行分区。算法
当使用范围分区时,请考虑如下几个规则:
一、每个分区都必须有一个VALUES LESS THEN子句,它指定了一个不包括在该分区中的上限值。分区键的任何值等于或者大于这个上限值的记录都会被加入到下一个高一些的分区中。
二、全部分区,除了第一个,都会有一个隐式的下限值,这个值就是此分区的前一个分区的上限值。
三、在最高的分区中,MAXVALUE被定义。MAXVALUE表明了一个不肯定的值。这个值高于其它分区中的任何分区键的值,也能够理解为高于任何分区中指定的VALUE LESS THEN的值,同时包括空值。
例一:
假设有一个CUSTOMER表,表中有数据200000行,咱们将此表经过CUSTOMER_ID进行分区,每一个分区存储100000行,咱们将每一个分区保存到单独的表空间中,这样数据文件就能够跨越多个物理磁盘。下面是建立表和分区的代码,以下:
CREATE TABLE CUSTOMER
(
CUSTOMER_ID NUMBER NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR2(30) NOT NULL,
LAST_NAME VARCHAR2(30) NOT NULL,
PHONE VARCHAR2(15) NOT NULL,
EMAIL VARCHAR2(80),
STATUS CHAR(1)
)
PARTITION BY RANGE (CUSTOMER_ID)
(
PARTITION CUS_PART1 VALUES LESS THAN (100000) TABLESPACE CUS_TS01,
PARTITION CUS_PART2 VALUES LESS THAN (200000) TABLESPACE CUS_TS02
)
例二:按时间划分数据库
CREATE TABLE ORDER_ACTIVITIES
(
ORDER_ID NUMBER(7) NOT NULL,
ORDER_DATE DATE,
TOTAL_AMOUNT NUMBER,
CUSTOTMER_ID NUMBER(7),
PAID CHAR(1)
)
PARTITION BY RANGE (ORDER_DATE)
(
PARTITION ORD_ACT_PART01 VALUES LESS THAN (TO_DATE('01- MAY -2003','DD-MON-YYYY')) TABLESPACEORD_TS01,
PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUN-2003','DD-MON-YYYY')) TABLESPACE ORD_TS02,
PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUL-2003','DD-MON-YYYY')) TABLESPACE ORD_TS03
)
例三:MAXVALUE
CREATE TABLE RangeTable
(
idd INT PRIMARY KEY ,
iNAME VARCHAR(10),
grade INT
)
PARTITION BY RANGE (grade)
(
PARTITION part1 VALUES LESS THEN (1000) TABLESPACE Part1_tb,
PARTITION part2 VALUES LESS THEN (MAXVALUE) TABLESPACE Part2_tb
);
4.2列表分区:
该分区的特色是某列的值只有几个,基于这样的特色咱们能够采用列表分区。
例一
CREATE TABLE PROBLEM_TICKETS
(
PROBLEM_ID NUMBER(7) NOT NULL PRIMARY KEY,
DESCRIPTION VARCHAR2(2000),
CUSTOMER_ID NUMBER(7) NOT NULL,
DATE_ENTERED DATE NOT NULL,
STATUS VARCHAR2(20)
)
PARTITION BY LIST (STATUS)
(
PARTITION PROB_ACTIVE VALUES ('ACTIVE') TABLESPACE PROB_TS01,
PARTITION PROB_INACTIVE VALUES ('INACTIVE') TABLESPACE PROB_TS02
例二
CREATE TABLE ListTable
(
id INT PRIMARY KEY ,
name VARCHAR (20),
area VARCHAR (10)
)
PARTITION BY LIST (area)
(
PARTITION part1 VALUES ('guangdong','beijing') TABLESPACE Part1_tb,
PARTITION part2 VALUES ('shanghai','nanjing') TABLESPACE Part2_tb
);
)
4.3 散列分区:
这类分区是在列值上使用散列算法,以肯定将行放入哪一个分区中。当列的值没有合适的条件时,建议使用散列分区。
散列分区为经过指定分区编号来均匀分布数据的一种分区类型,由于经过在I/O设备上进行散列分区,使得这些分区大小一致。
例一:
CREATE TABLE HASH_TABLE
(
COL NUMBER(8),
INF VARCHAR2(100)
)
PARTITION BY HASH (COL)
(
PARTITION PART01 TABLESPACE HASH_TS01,
PARTITION PART02 TABLESPACE HASH_TS02,
PARTITION PART03 TABLESPACE HASH_TS03
)
简写:
CREATE TABLE emp
(
empno NUMBER (4),
ename VARCHAR2 (30),
sal NUMBER
)
PARTITION BY HASH (empno) PARTITIONS 8
STORE IN (emp1,emp2,emp3,emp4,emp5,emp6,emp7,emp8);
hash分区最主要的机制是根据hash算法来计算具体某条纪录应该插入到哪一个分区中,hash算法中最重要的是hash函数,Oracle中若是你要使用hash分区,只需指定分区的数量便可。建议分区的数量采用2的n次方,这样可使得各个分区间数据分布更加均匀。
4.4 组合范围散列分区
这种分区是基于范围分区和列表分区,表首先按某列进行范围分区,而后再按某列进行列表分区,分区之中的分区被称为子分区。
CREATE TABLE SALES
(
PRODUCT_ID VARCHAR2(5),
SALES_DATE DATE,
SALES_COST NUMBER(10),
STATUS VARCHAR2(20)
)
PARTITION BY RANGE(SALES_DATE) SUBPARTITION BY LIST (STATUS)
(
PARTITION P1 VALUES LESS THAN(TO_DATE('2003-01-01','YYYY-MM-DD'))TABLESPACE rptfact2009
(
SUBPARTITION P1SUB1 VALUES ('ACTIVE') TABLESPACE rptfact2009,
SUBPARTITION P1SUB2 VALUES ('INACTIVE') TABLESPACE rptfact2009
),
PARTITION P2 VALUES LESS THAN (TO_DATE('2003-03-01','YYYY-MM-DD')) TABLESPACE rptfact2009
(
SUBPARTITION P2SUB1 VALUES ('ACTIVE') TABLESPACE rptfact2009,
SUBPARTITION P2SUB2 VALUES ('INACTIVE') TABLESPACE rptfact2009
)
)
4.5 复合范围散列分区:
这种分区是基于范围分区和散列分区,表首先按某列进行范围分区,而后再按某列进行散列分区。
create table dinya_test
(
transaction_id number primary key,
item_id number(8) not null,
item_description varchar2(300),
transaction_date date
)
partition by range(transaction_date)subpartition by hash(transaction_id) subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03)
(
partition part_01 values less than(to_date(‘2006-01-01’,’yyyy-mm-dd’)),
partition part_02 values less than(to_date(‘2010-01-01’,’yyyy-mm-dd’)),
partition part_03 values less than(maxvalue)
);
五 有关表分区的一些维护性操做:
5.1 添加分区
如下代码给SALES表添加了一个P3分区
ALTER TABLE SALES ADD PARTITION P3 VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD'));
注意:以上添加的分区界限应该高于最后一个分区界限。
如下代码给SALES表的P3分区添加了一个P3SUB1子分区
ALTER TABLE SALES MODIFY PARTITION P3 ADD SUBPARTITION P3SUB1 VALUES('COMPLETE');
5.2 删除分区
如下代码删除了P3表分区:
ALTER TABLE SALES DROP PARTITION P3;
在如下代码删除了P4SUB1子分区:
ALTER TABLE SALES DROP SUBPARTITION P4SUB1;
注意:若是删除的分区是表中惟一的分区,那么此分区将不能被删除,要想删除此分区,必须删除表。
5.3 截断分区
截断某个分区是指删除某个分区中的数据,并不会删除分区,也不会删除其它分区中的数据。当表中即便只有一个分区时,也能够截断该分区。经过如下代码截断分区:
ALTER TABLE SALES TRUNCATE PARTITION P2;
经过如下代码截断子分区:
ALTER TABLE SALES TRUNCATE SUBPARTITION P2SUB2;
5.4 合并分区
合并分区是将相邻的分区合并成一个分区,结果分区将采用较高分区的界限,值得注意的是,不能将分区合并到界限较低的分区。如下代码实现了P1 P2分区的合并:
ALTER TABLE SALES MERGE PARTITIONS P1,P2 INTO PARTITION P2;
5.5 拆分分区
拆分分区将一个分区拆分两个新分区,拆分后原来分区再也不存在。注意不能对HASH类型的分区进行拆分。
ALTER TABLE SALES SBLIT PARTITION P2 AT(TO_DATE('2003-02-01','YYYY-MM-DD')) INTO (PARTITION P21,PARTITION P22);
5.6 接合分区(coalesca)
结合分区是将散列分区中的数据接合到其它分区中,当散列分区中的数据比较大时,能够增长散列分区,而后进行接合,值得注意的是,接合分区只能用于散列分区中。经过如下代码进行接合分区:
ALTER TABLE SALES COALESCA PARTITION;
5.7 重命名表分区
如下代码将P21更改成P2
ALTER TABLE SALES RENAME PARTITION P21 TO P2;
5.8 相关查询
跨分区查询
select sum( *) from
(select count(*) cn from t_table_SS PARTITION (P200709_1)
union all
select count(*) cn from t_table_SS PARTITION (P200709_2)
);
查询表上有多少分区
SELECT * FROM useR_TAB_PARTITIONS WHERE TABLE_NAME='tableName'
查询索引信息
select object_name,object_type,tablespace_name,sum(value)
from v$segment_statistics
where statistic_name IN ('physical reads','physical write','logical reads')and object_type='INDEX'
group by object_name,object_type,tablespace_name
order by 4 desc
--显示数据库全部分区表的信息:
select * from DBA_PART_TABLES
--显示当前用户可访问的全部分区表信息:
select * from ALL_PART_TABLES
--显示当前用户全部分区表的信息:
select * from USER_PART_TABLES
--显示表分区信息 显示数据库全部分区表的详细分区信息:
select * from DBA_TAB_PARTITIONS
--显示当前用户可访问的全部分区表的详细分区信息:
select * from ALL_TAB_PARTITIONS
--显示当前用户全部分区表的详细分区信息:
select * from USER_TAB_PARTITIONS
--显示子分区信息 显示数据库全部组合分区表的子分区信息:
select * from DBA_TAB_SUBPARTITIONS
--显示当前用户可访问的全部组合分区表的子分区信息:
select * from ALL_TAB_SUBPARTITIONS
--显示当前用户全部组合分区表的子分区信息:
select * from USER_TAB_SUBPARTITIONS
--显示分区列 显示数据库全部分区表的分区列信息:
select * from DBA_PART_KEY_COLUMNS
--显示当前用户可访问的全部分区表的分区列信息:
select * from ALL_PART_KEY_COLUMNS
--显示当前用户全部分区表的分区列信息:
select * from USER_PART_KEY_COLUMNS
--显示子分区列 显示数据库全部分区表的子分区列信息:
select * from DBA_SUBPART_KEY_COLUMNS
--显示当前用户可访问的全部分区表的子分区列信息:
select * from ALL_SUBPART_KEY_COLUMNS
--显示当前用户全部分区表的子分区列信息:
select * from USER_SUBPART_KEY_COLUMNS
--怎样查询出oracle数据库中全部的的分区表
select * from user_tables a where a.partitioned='YES'
--删除一个表的数据是
truncate table table_name;
--删除分区表一个分区的数据是
alter table table_name truncate partition p5;
六 、分区表的索引
对于分区表,能够创建不分区索引。也就是说表分区,可是索引不分区。如下着重介绍分区表的分区索引。oracle
索引与表同样,也能够分区。索引分为两类:locally partition index(局部分区索引)、globally partition index(全局分区索引)。less
6.1. 局部分区索引(locally partition index)
局部分区索引随表对索引完成相应的分区,即索引会使用与表相同的机制进行分区,每一个表分区都有一个索引分区,而且只索引该表分区。函数
6.1.1 局部索引分类
▶ 局部前缀索引(local prefixed index):以分区键做为索引定义的第一列工具
▶ 局部非前缀索引(local nonprefixed index):分区键没有做为索引定义的第一列post
注意:判断局部索引是前缀仍是非前缀的只须要看分区键是否做为索引定义的第一列性能
示例语句spa
--范围分区
--建立表
create table student_range_part(
stu_id varchar2(4),
stu_name varchar2(100), --姓名
sex varchar2(1), --性别 1 男 2 女 0 未知
credit integer default 0
)
partition by range (credit)
(
partition student_part1 values less than (60) tablespace kdhist_data,
partition student_part2 values less than (70) tablespace kdhist_data,
partition student_part3 values less than (80) tablespace kdhist_data,
partition student_part4 values less than (maxvalue) tablespace kdhist_data
);
--建立局部前缀索引;分区键(credit)做为索引定义的第一列
create index local_prefixed_index on student_range_part (credit, stu_id) local;
--建立局部非前缀索引;分区键未做为索引定义的第一列
create index local_nonprefixed_index on student_range_part (stu_id, credit) local;
6.1.2 局部索引示例
--①
select * from student_range_part where credit = &credit and stu_id = &stu_id;
--②
select * from student_range_part where stu_id = &stu_id;
对于以上两个查询来讲,若是查询第一步是走索引的话,则:
局部前缀索引 local_prefixed_index 只对 ① 有用;
局部非前缀索引 local_nonprefixed_index 则对 ① 和 ② 均有用;
若是你有多个相似 ① 和 ② 的查询的话,则能够考虑创建局部非前缀索引;若是日常多使用查询 ① 的话,则能够考虑创建局部前缀索引;
小结:
分区表通常使用局部索引。重点在于如何选择分区表和局部索引类型。
6.2. 全局分区索引(globally partition index)
索引按范围(Range)或散列(Hash,Oracle 10g中引入)进行分区,一个分区索引(全局)可能指向任何(或所有的)表分区。
对于全局分区索引来讲,索引的实际分区数可能不一样于表的分区数量;
全局索引的分区机制有别于底层表,例如表能够按 credit 列划分为10个分区,表上的一个全局索引能够按stu_id 列划分为5个分区。
与局部索引不一样,全局索引只有一类,即全局前缀索引(prefixed global index),索引分区键必须做为索引定义的第一列,不然执行会报错。
--范围分区
--建立表
create table student_range_part(
stu_id varchar2(4),
stu_name varchar2(100), --姓名
sex varchar2(1), --性别 1 男 2 女 0 未知
credit integer default 0
)
partition by range (credit)
(
partition student_part1 values less than (60) tablespace kdhist_data,
partition student_part2 values less than (70) tablespace kdhist_data,
partition student_part3 values less than (80) tablespace kdhist_data,
partition student_part4 values less than (maxvalue) tablespace kdhist_data
);
--建立按age进行范围分区的全局分区索引
create index global_index on student_range_part(credit) global
partition by range (credit)
(
partition index_part1 values less than (60),
partition index_part2 values less than (80),
partition index_partmax values less than (maxvalue)
);
注意:
全局索引要求最高分区(即最后一个分区)必须有一个值为 maxvalue 的最大上限值,这样能够确保底层表的全部行都能放在这个索引中;
通常状况下,大多数分区操做(如删除一个旧分区)都会使全局索引无效,除非重建全局索引,不然没法使用
全局索引示例
全局索引通常用于数据仓库,许多数据仓库系统都存在大量的数据出入,如典型的数据“滑入滑出”(即删除表中最旧的分区,并为新加载的数据增长一个新分区)。
① 去除老数据:最旧的分区要么被删除,要么建立一个新表,将最旧的分区数据存入,从而对旧数据进行归档;
② 加载新数据并创建索引:将新数据加载到一个“工做”表中,创建索引并进行验证;
③ 关联新数据:一旦加载并处理了新数据,数据所在的表会与分区表中的一个空分区交换,将表中的这些新加载的数据变成分区表中的一个分区(分区表会变得更大)
对于全局索引来讲,这样增删分区的过程,意味着该全局索引的失效,需重建全局索引;
在 Oracle 9i 以后,能够在分区操做期间使用 UPDATE GLOBAL INEXES 子句来维护全局索引,这意味着当在分区上执行删除、分解或其余操做时,Oracle会对原先创建的全局索引执行必要的修改,以保证它是最新的。
--删除student_range_part表中的index_part1分区,同时同步维护全局索引
alter table student_range_part drop partition index_part1 update global indexes;
使用 UPDATE GLOBAL INEXES子句后,在删除一个分区时,必须删除可能指向该分区的全部全局索引条目;
执行表与分区的交换时,必须删除指向原数据的全部全局索引条目,再插入指向刚加载的数据的新条目;
如此一来 ALTER 命令执行的工做量会大幅增长;
小结:
分区操做执行完成后重建全局索引方式占用的数据库资源更少,所以完成的相对“更快”,可是会带来显著的“停机时间”(重建索引时会有一个可观的不可用窗口);
在分区操做执行的同时执行 UPDATE GLOBAL INDEXES 子句方式会占用更多的资源,且可能须要花费更长的时间才能完成操做,但好处是不会带来任何的停机时间。
即便是数据仓库,除非特殊需求,不然这个建立局部索引便可。